Showing posts with label chapter 6 exercise. Show all posts
Showing posts with label chapter 6 exercise. Show all posts

Thursday, 1 June 2017

Chapter 6 // Exercise 10 - Principles & Practice Using C++

Chapter 6 // Exercise 10


"Design a program that asks users for two numbers, and asks them whether they want to calculate permutations or combinations, and prints out the result. This will have several parts. Do an analysis of the above requirements. Write exactly what the program will have to do. Then, go into the design phase. Write pseudo code for the program and break it into sub-components. This program should have error-checking. Make sure that all erroneous inputs will generate good error messages."

OK, at first this sounds pretty daunting and there are some rather large(ish) equations given in the book however when you actually break down what he's asking, it becomes a pretty simple task.

We have already been given the formulas so it's just a matter of getting some numbers from the user and throwing them at some functions which solve the formulas, the pseudo code could look like this:

Ask user for two numbers
>numbers
Does user want combination or permutation?
>answer

If answer == Combination
       pass numbers to function and place into equation
       print combinations

If answer == Permutation
       pass numbers to function and place into equation
       print permutations

Pause & Quit

For some more information on combinations and permutations, check out this site. After reading this, it would appear that there are two ways to solve each problem but Bjarne only gives the formula to solve combinations without repetition. According to the site above, solving combinations with repetition requires a slightly different formula. So which one do we use?

For this exercise, I'm just going to stick to the formulas given.



#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <cctype>

#undef max //undefine max so it can be used in getInt

using namespace std;

double a;
double b;

//this function was taken from http://www.cplusplus.com/forum/beginner/21595/
//it makes sure that only numbers can be used
double getInt()
{
  double x = 0;

  while (!(cin >> x)) 
  {
    cin.clear();
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    cout << "You need to input a number: ";
 }

 return x;
}

//this gets two numbers and asks if the users wants permutations or combinations
//erroneous input is checked by getInt() and only allows P or C to be chosen
char permOrComb()
{
  cout << "Please enter the maximum amount of numbers: " << endl;
  a = getInt();
  cout << "Please enter how many numbers are needed: " << endl;
  b = getInt();

  cout << "\n\nWould you like to perform Permutation (p) or Combination (c)?: " << endl;
  char answer;
  cin >> answer;
  answer = toupper(answer); //converts letter to upper case

  while (answer != 'P' && answer != 'C')
  {
    cout << "You need to enter (p) or (c): ";
    cin >> answer;
    answer = toupper(answer);
  }

  return answer;
}

//this works out a factorial and returns the result
double getFactorial(double n)
{
  if (n == 0)
     n = 1;

  double factorial = n;

  for (double i = n - 1; i > 1; --i)
  {
    factorial = factorial*i;
  }

  return factorial;
}

//this solves permutations
double getPermutation()
{
  double p;
  double temp = a - b;

  //if a - b is a minus, flip it to positive
  if (temp < 0)
    temp *= -1;

  p = (getFactorial(a) / getFactorial(temp));

  return p;
}

//this solves combinations (where there is no repitition)
double getCombination()
{
  double c;
  double tempP = getPermutation();

  c = (tempP) / (getFactorial(b));
 
  return c; 
}

bool getQuit()
{
  char temp;
  bool qTemp = true;

  cout << "\n\nWould you like to quit (q) or continue (c): ";
  cin >> temp;
  temp = toupper(temp);

  while (temp != 'Q' && temp != 'C')
  {
    cout << "You need to enter (q) or (c): ";
    cin >> temp;
    temp = toupper(temp);
  }

  if (temp == 'Q')
    qTemp = false;
  if (temp == 'P')
    qTemp = true;

  return qTemp;
}


int main()
{
  bool quit = true;

  while (quit)
  {
    char answer = permOrComb();

    if (answer == 'P')
    {
      double temp = getPermutation();
      cout << "\nThere are " << temp << " permutations with these numbers.\n";
      quit = getQuit();
    }

   if (answer == 'C')
   {
     double temp = getCombination();
     cout << "\nThere are " << temp << " combinations with these numbers.\n";
     quit = getQuit();
   }

  }

  return 0;
}


I used the factorial function I created in Chapter 6 - Exercise 3 to solve for ! and then it was simply a case of checking for erroneous input. 

As I said above, this only solves combinations where there is no repetition, but it would be simple to create another function which solves for that using the formula given from the link above. Then just ask the user if repetition is allowed or not.

Monday, 26 December 2016

Chapter 6 // Exercise 9 - Principles & Practice Using C++

Chapter 6 // Exercise 9

Write a program that reads digits and composes them into integers. For example 123 is read as the characters 1, 2 and 3. The program should output "123 is 1 hundred and 2 tens and 3 ones". The number should be output as an int value. Handle numbers with one, two, three or four digits.

Hint: To get the integer value 5 from the character '5' subtract '0', that is '5'-'0'==5.


#include "stdafx.h"
#include <vector>
#include <string>
void pause();
void getNumbers();
void printNumbers();
using namespace std;
vector <int> digits;
char er = 'n'; //for error checking

int main()
{
 //get the numbers and convert them to an int from string
 getNumbers();

 //print the numbers out
 printNumbers();


 //ask for letter to quit the program
 pause();

 return 0;
}


void getNumbers()
{
 er = 'n';
 cout << "Please enter a number with up to 4 digits: ";
 string x;
 cin >> x; 

 //error checking
 for (int i = 0; i < x.size(); ++i)
 {
  for (char n = 'a'; n < 'z'; ++n)
  {
   while (x[i] == n)
   {
    er = 'y';
    cout << "That is not a number. Sorry.\n";
    return;
   }  
  }

  int num = x[i] - '0'; //converts letter to int
  digits.push_back(num); //pushes back into int vector
 }
}

void printNumbers()
{
 //continue to get input while er is equal to y
 while (er == 'y')
  getNumbers();

 for (int i = 0; i < digits.size(); ++i)
  cout << digits[i];

 cout << " is ";

 if (digits.size() == 4)
 {
  if (digits[0] == 1)
   cout << digits[0] << " thousand and ";
  else
   cout << digits[0] << " thousands and ";

  if (digits[1] == 1)
   cout << digits[1] << " hundred and ";
  else
   cout << digits[1] << " hundreds and ";

  if (digits[2] == 1)
   cout << digits[2] << " ten and ";
  else
   cout << digits[2] << " tens and ";

  cout << digits[3] << " ones.\n";
 }


 if (digits.size() == 3)
 {
  if (digits[0] == 1)
   cout << digits[0] << " hundred and ";
  else
   cout << digits[0] << " hundreds and ";

  if (digits[1] == 1)
   cout << digits[1] << " ten and ";
  else
   cout << digits[1] << " tens and ";

  cout << digits[2] << " ones.\n";
 }


 if (digits.size() == 2)
 {
  if (digits[0] == 1)
   cout << digits[0] << " ten and ";
  else
   cout << digits[0] << " tens and ";
  cout << digits[1] << " ones.\n";
 }

 if (digits.size() == 1)
 {
  cout << digits[0] << " ones.\n";
 }

}

void pause()
{
 cout << "\n\nPlease enter a letter: ";
 char key;
 cin >> key;
}


I'm sure there must be a much easier way to print the digits grammatically however I decided to just do this by brute force because this small program doesn't really take up any memory by doing it this way, nor does it slow it down. 

At first when I read this question I was like "what on earth does he want me to do now?" I didn't know if he wanted us to write into a char but then a char can't hold more than single character, so I thought about a vector of chars and pushing them back but that would require at least 5 different chars to push back. So I went with a string and I actually learnt something very useful today.

So string has similar functions as vector, I knew that I could get the size of it by using .size after the variable to return how many characters had been inputted. However on a whim I decided to see what would happen if I took away '0' from the character within the string, as suggested by Bjarne in the book. And it worked, it returned a number which I applied to a interger called num and then pushed that into a vector so printNumbers() had them all in one place.

Also, as a little extra this includes error checking. This doesn't allow any letters and will only allow numbers. I did this by comparing whatever the current character of x was to the alphabet using a for loop. For example, if the string x was equal to k then k would be compared to each letter of the alphabet and if it was equal to one then it returns to main and executes the next function. However the char 'er' has been set to 'y' so it will keep calling getNumbers() until er is equal to 'n'. It took me a while to get this error check working, so I'm pretty proud it does.

Thursday, 29 September 2016

Chapter 6 // Exercise 8 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 6 // Exercise 8

Redo the "Bulls & Cows" game from exercise 12 in Chapter 5 to use four letters rather than four digits.



#include "stdafx.h"
#include "std_lib_facilities_new_version.h"
using namespace std;

void getSeed();
void printRules();
void startGame();
void getLetters();
void compareLetters();
char assignLoop();
vector<char> fourLetters{ 0,0,0,0 };
vector<char> guess{ 0,0,0,0 };

int main()
try
{
char loop = 'y';

while (loop == 'y')
{
//get number for seed  & assign letters to fourLetters
getSeed();

//print rules of game
printRules();

//begin the game and keep going till user decides to quit
startGame();

//ask if you want to play again
loop = assignLoop();
}

keep_window_open();

return 0;
}


catch (exception& e)
{
cerr << "Error: " << e.what() << '\n';
keep_window_open();
return 1;
}

//produces random number which corralates to ASCII lower case alphabet
char getRandLetter()
{
char randNum = (rand()%(122 - 97 + 1)) + 97; // produces random number between 97 and 122
return randNum;
}

//get seed for rand num and assign letters to comp's four letters
void getSeed()
{
cout << "Please enter a number(any number):\n";
int n;
cin >> n;

srand(n);
for (int i = 0; i < fourLetters.size(); ++i)
{
fourLetters[i] = getRandLetter();
}

sort(fourLetters); //to compare if any are the same

for (int i = 1; i < fourLetters.size(); ++i)
{
while (fourLetters[i] == fourLetters[i - 1])
{
fourLetters[i] = getRandLetter();
}
}

}



void printRules()
{
cout << "//RULES//";
cout << "\nLets Play Bulls & Cows.\n";
cout << "Guess the 4 letters.\n";
cout << "If a letter is right in the right position you will get a bull.\n";
cout << "If the letter is right in the wrong position you will get a cow.\n";
cout << "\nGuess a letter a-z. Each letter must be different and lower case. \n\n";
}

void startGame()
{
while (guess != fourLetters)
{
//get user letters
getLetters();
//compare user and random letters for bulls & cows
compareLetters();
}
}

void getLetters()
{

vector<string>n = { "1st Letter: ", "2nd Letter: ", "3rd Letter: ", "4th Letter: " };

for (int i = 0; i < 4; ++i)
{
cout << n[i];
char letter;
cin >> letter;

if (letter < 'a' || letter > 'z')
error("You can only use lower case.\n");

guess[i] = letter;
}

cout << "Your guess: ";

for (int i = 0; i < 4; ++i)
{
cout << guess[i] << " ";
}

cout << '\n';
}

void compareLetters()
{
for (int i = 0; i < 4; ++i)
{
for (int n = 0; n < 4; ++n)
{
if (guess[i] == fourLetters[n])
{
if (i == n)
cout << "1 Bull(" << guess[i] << ")";
else
cout << "1 Cow(" << guess[i] << ")";
}
}
}
}

char assignLoop()
{
cout << "\n\nCongratz! You did it!\n";
cout << "Would you like to play again? y / n:\n";
char l;
cin >> l;
while (l != 'y' && l != 'n')
{
cout << "Invalid answer, try again. y / n:\n";
cin >> l;
}

return l;
}



This one took a while as I figured out how to perfect a few things. The original exercise had you guess a number 1 - 9, this one a letter a -z. Since int and char are interchangeable I simply changed most of the code to char however when it came to randomizing what letters you would get I had to find a new function.


The one I've got accepts a max and a min value, for us we want between 97 and 122 as these are the numbers for the characters a - z. I then just assigned one of the generated numbers to the guess vector. When looking to see if any of them were the same I realised my prior function wasn't exactly perfect and would sometimes allow the same numbers. I've corrected it on this one by sorting them first. This does give the letters some predictability by putting them in order however not all the time as if some are the same they will be changed to another generated number.



Tuesday, 27 September 2016

Chapter 6 // Exercise 7 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 6 // Exercise 7

Write a grammar for bitwise logical expressions.  A bitwise logical expression is much like an arithmetic expression except that the operators are ! (not), ~ (complement), & (and), | (or) and ^ (exclusive or).

Each operator does its operation to each bit of its integer operands. ! and ~ are prefix unary operators.

binds tighter than a | (just as * binds tighter than +) so that x|y^z means x|(y^z) rather than (x|y)^z. The & operator binds tighter than ^ so that x^y&z means x^(y&z).

Expression:
    Third Term
    Expression "|" Third Term

Third Term:
    Second Term
    Third Term "^" Second Term

Second Term:
    First Term
    Second Term "&" First Term

First Term:
    Primary
    First Term "!" Primary
    First Term "~" Primary

Primary:
    Object   //int, char, string etc
    "(" Expression ")"


Following the example earlier in chapter 6 I think this is how it would be done although I'm not entirely sure. English was always my best subject but grammar in programming is throwing my brain for a loop.

EDIT 07/10/2019 - This was almost correct the first time I did it. However, now I understand his thought process a little better on grammars I've realised that the First Term section is incorrect. "!" and "~" are always pre-fix operators and as such it will be sufficient for First term to look like this:
Primary
"!" Primary
"~" Primary
This way, they will always affect the Primary instead of the left value. Here is an updated version on GitHub.

Friday, 23 September 2016

Chapter 6 // Exercises 5, 6 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 6 // Exercise 5

Add the article the to the "English" grammar in 6.4.1, so that it can describe sentences such as "The birds fly but the fish swim."

I'm not sure quite what he wants us to do in this one. Make a program or just change the psuedocode? Either way the word 'the' is extremely complicated and has many different uses. It's doesn't always come before or after a verb, same with a noun and it's not a conjunction (something that joins sentences together). 

If he just wants us to change the psuedocode so it always comes before a noun (like he's put in his example) then it would be like this:


Sentence:
The Noun Verb
Sentence Conjuction Sentence

Conjuction:
and
or
but

Noun:
birds
fish
C++

The:
the

Verb:
rules
fly 
swim

I think this would also give you "The c++ rules", which is bad grammar because c++ doesn't denote something plural or a direct object (as opposed to saying 'the rules' where rules denotes the plural of rule) But I don't think we're creating Microsoft Word just yet, so I'm going to leave this one where it is.

Chapter 6 // Exercise 6


Write a program that checks if a sentence is correct according to the "English" grammar in 6.4.1. Assume that every sentence is terminated by a full stop (.) surrounded by white space. For example, birds fly but the fish swim .  is a sentence, but birds fly but the fish swim (terminating dot missing) and birds fly but the fish swim. (no space before dot) are not. For each sentence entered, the program should simply respond "OK" or "not OK". Hint: Don't bother with tokens; just read in a string using >>.

 I honestly didn't know what to make of this so here is his answer:

Chapter 6 exercise 6

Reading through it, it uses bools and I just can't wrap my head around them. It's just like minecraft with the not gates, I understand it flips it but I just don't get the whole 'true' 'false' thing.

Overall these two exercises were just



to me.

EDIT 07/10/2019 - I have now completed these two exercises found on GitHub here. This took me a while as I started getting pedantic about how to parse the sentence. I eventually went with a very hacky way of doing things as I was starting to run out of time. Eventually, I'll go back and refactor the code again to make it a little more …elegant shall we say. I started doing it how he has done it without realising it, but it doesn't allow for all the sentence types I don't think. I do like the idea of parsing the sentence into a wordtype vector as you can create verb/noun vectors and add more words to them and when deciding what they are, use a for loop to loop through each vector. Then creating a function which checks sentence structure shouldn't be too much hassle. I say shouldn't...

Wednesday, 21 September 2016

Chapter 6 // Exercise 4 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 6 // Exercise 4

Define a class Name_value that holds a string and a value. Rework exercise 19 in Chapter 4 to use a vector<Name_value> instead of two vectors.

#include "stdafx.h"
#include "std_lib_facilities_new_version.h"
using namespace std;

class Name_value
{
public:
string name;
int score;
};

vector<Name_value> n_s;

void getData()
{
cout << "Please enter a name, press enter, then input the score. To stop input enter 'NoName' in name and 0 in scores.\n";

Name_value data;  //variable that holds a string and int pair
char loop = 'y';

//get names and scores
while (loop == 'y')
{
cout << "Name: ";
cin >> data.name;
cout << "Score: ";
cin >> data.score;
for (int i = 0; i < n_s.size(); ++i)
{
while (n_s[i].name == data.name)
{
cout << "Sorry, that name has already been entered. Please Re-Name it: \n" << endl;
cin >> data.name;
}
}

if (data.name == "NoName" && data.score == 0)
{
loop = 'n';
}

n_s.push_back(data);  //pushes the string and int pair into the vector together
}

}

void printData()
{
cout << '\n';

//print them out
for (int x = 0; x < n_s.size() - 1; ++x)
{
cout << n_s[x].name << '\t' << n_s[x].score << '\n';
}

}

int main()
{

getData();

printData();

keep_window_open();

return 0;

}


This took some thought but didn't take me too long. The bit I tripped up on was pushing back the data into the class vector. Originally I had separate variables and was trying to push them in like this:
     n_s.name.push_back(inputname);
but obviously that wouldn't work because the compiler thought name was a function. Instead I realised I could just create a variable that held both and then push the entire variable into it's respective slots in the vector.

Monday, 19 September 2016

Chapter 6 // Exercise 3 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 6 // Exercise 3

Add a factorial operator: use suffix ! operator to represent "factorial." For example, the expression 7! means 7*6*5*4*3*2*1. Make ! bind tighter than * and /; that is 7*8! means 7*(8!) rather than (7*8)!. begin by modifying the grammar to account for a higher-level operator. To agree with the standard mathematical definition of factorial, let 0! evaluate to 1.
Hint: The calculator functions deals with doubles, but factorial is defined only for ints, so just for x!, assign the x to an int and calculate the factorial of that int.

Sweet baby Jesus and the orphans. I read this and thought "what the hell is a factorial? Is he just making shit up now?". After some researching on factorials it's basically represented like this n(n-1). To start off I wrote a program that works out a factorial and got it working just so I understood what I was working with. Below is the program for documentation purposes:

#include "stdafx.h"
#include "std_lib_facilities_new_version.h"
using namespace std;

int getFactorial(int n)
{
if (n == 0)
n = 1;

int factorial = n;

for (int i = n - 1; i > 1; --i)
{
factorial = factorial*i;
}

return factorial;
}

int main()
{
cout << "Please enter a number to find the factorial:\n";
cout << "Press x to quit.\n";

while (cin)
{
int n;
cin >> n;

int f = getFactorial(n);

cout << n << "!" << " = " << f << endl;

cout << "Please enter a number to find the factorial:\n";
}

keep_window_open();

return 0;

}

The for loop in getFactorial() starts with i assigned -1 of whatever the number you input. So if n was 5, i will equal 4. Factorial is then assigned itself; multiplied by i. So for each iteration, i minuses 1 until it reaches 1 and multiplies with the previous answer.

So now we know how do do a factorial, it's just a matter of implementing it within the calculator program. First I added '!' to the case list in get():

Token Token_stream::get()
{
if (full)
{       // do we already have a Token ready?
// remove token from buffer
Token_stream::full = false;
return buffer;
}


char ch;
cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)

switch (ch)
{
case '=':    // for "print"
case 'x':    // for "quit"


case '(': case ')': case '+': case '-': case '*': case '/':
case '{': case '}': case '!':
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.putback(ch);         // put digit back into the input stream
cin >> val;              // read a floating-point number
return Token('#', val);   // let '#' represent "a number"
}

default:
error("Bad token");
}

}

Then, I created a new function called int higherTerm() which is obviously higher than term. This is meant to illustrate to the computer that '!' binds tighter than '*' or '/'. This code is placed directly after primary().

int getFactorial(int n) //function that deals with factorials
{
if (n == 0)
n = 1;

int factorial = n;

for (int i = n - 1; i > 1; --i)
{
factorial = factorial*i;
}

return factorial;
}

//------------------------------------------------------------------

//deal with !
int higherTerm()
{
double left = primary();
Token t = ts.get();        // get the next token from token stream

while (true)
{
switch (t.kind)
{
case '!':
{
int ileft = left; //changing the double to an int, this will round down
left = getFactorial(ileft);
t = ts.get();
break;
}

default:
ts.putback(t);     // put t back into the token stream

return left;
}
}


}

//------------------------------------------------------------------

// deal with *, /
double term()
{
double left = higherTerm();
Token t = ts.get();        // get the next token from token stream

while (true)
{
switch (t.kind)
{
case '*':
{
left *= higherTerm();
t = ts.get();
break;
}

case '/':
{
double d = higherTerm();
if (d == 0) error("divide by zero");
left /= d;
t = ts.get();
break;
}

default:
ts.putback(t);     // put t back into the token stream

return left;
}
}
}



So higherTerm() now gets the primary, the function checks to see if there is a '!' after the primary, if not, passes the number on down the food chain. term() now calls to higherTerm() so it gets whatever has been left over from there.

Here is the full program:


#include "stdafx.h"

#include "std_lib_facilities_new_version.h"
using namespace std;

double val; //global variable
//------------------------------------------------------------------------------

class Token {
public:
char kind;        // what kind of token
double value;     // for numbers: a value 
Token(char ch)    // make a Token from a char
:kind(ch), value(0) { }
Token(char ch, double val)     // make a Token from a char and a double
:kind(ch), value(val) { }
};

//------------------------------------------------------------------------------

class Token_stream {
public:
Token_stream();   // make a Token_stream that reads from cin
Token get();      // get a Token (get() is defined elsewhere)
void putback(Token t);    // put a Token back
private:
bool full;        // is there a Token in the buffer?
Token buffer;     // here is where we keep a Token put back using putback()
};

//------------------------------------------------------------------------------

// The constructor just sets full to indicate that the buffer is empty:
Token_stream::Token_stream()
:full(false), buffer(0)    // no Token in buffer
{
}

//------------------------------------------------------------------------------

// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
if (full) error("putback() into a full buffer");
buffer = t;       // copy t to buffer
full = true;      // buffer is now full
}

//------------------------------------------------------------------------------

Token Token_stream::get()
{
if (full)
{       // do we already have a Token ready?
// remove token from buffer
Token_stream::full = false;
return buffer;
}


char ch;
cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)

switch (ch)
{
case '=':    // for "print"
case 'x':    // for "quit"


case '(': case ')': case '+': case '-': case '*': case '/':
case '{': case '}': case '!':
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.putback(ch);         // put digit back into the input stream
cin >> val;              // read a floating-point number
return Token('#', val);   // let '#' represent "a number"
}

default:
error("Bad token");
}
}

//------------------------------------------------------------------------------

Token_stream ts;        // provides get() and putback() 

//------------------------------------------------------------------------------

double expression();    // declaration so that primary() can call expression()

int getFactorial(int n);

//------------------------------------------------------------------------------

// deal with numbers and parentheses
double primary()
{
Token t = ts.get();

switch (t.kind)
{

case '{':     // handle '{' expression '}'
{
double d = expression();
t = ts.get();
if (t.kind != '}')
error("'}' expected");
return d;
break;
}

case '(':    // handle '(' expression ')'
{
double d = expression();
t = ts.get();
if (t.kind != ')') error("')' expected)");
return d;
break;
}

case '#':            // we use '#' to represent a number
{
return t.value;  // return the number's value
break;
}

default:
error("primary expected");
}
}

//------------------------------------------------------------------------------

int getFactorial(int n) //function that deals with factorials
{
if (n == 0)
n = 1;

int factorial = n;

for (int i = n - 1; i > 1; --i)
{
factorial = factorial*i;
}

return factorial;
}

//------------------------------------------------------------------------------

//deal with !
int higherTerm()
{
double left = primary();
Token t = ts.get();        // get the next token from token stream

while (true)
{
switch (t.kind)
{
case '!':
{
int ileft = left; //changing the double to an int, this will round down
left = getFactorial(ileft);
t = ts.get();
break;
}

default:
ts.putback(t);     // put t back into the token stream

return left;
}
}
}



// deal with *, /
double term()
{
double left = higherTerm();
Token t = ts.get();        // get the next token from token stream

while (true)
{
switch (t.kind)
{
case '*':
{
left *= higherTerm();
t = ts.get();
break;
}

case '/':
{
double d = higherTerm();
if (d == 0) error("divide by zero");
left /= d;
t = ts.get();
break;
}

default:
ts.putback(t);     // put t back into the token stream

return left;
}
}
}

//------------------------------------------------------------------------------

// deal with + and -
double expression()
{
double left = term();      // read and evaluate a Term
Token t = ts.get();        // get the next token from token stream

while (true) {
switch (t.kind) {
case '+':
left += term();    // evaluate Term and add
t = ts.get();
break;
case '-':
left -= term();    // evaluate Term and subtract
t = ts.get();
break;
default:
ts.putback(t);     // put t back into the token stream
return left;       // finally: no more + or -: return the answer
}
}
}

//------------------------------------------------------------------------------

void printInstructions()
{
cout << "Welcome to our simple calculator!\n";
cout << "You can use + - / * and ! for factorial \n";
cout << "Press = to print the answer and x to exit.\n";
cout << "Please enter expressions using floating-point numbers:\n" << endl;
}

//------------------------------------------------------------------------------

int main()
try
{
printInstructions();

val = 0;
while (cin)
{
Token t = ts.get();

while (t.kind == '=')
t = ts.get();

if (t.kind == 'x')
{
return 0;
}

ts.putback(t);
cout << expression() << '\n';
}
return 0;
}
catch (exception& e) {
cerr << "error: " << e.what() << '\n';
keep_window_open();
return 1;
}
catch (...) {
cerr << "Oops: unknown exception!\n";
keep_window_open();
return 2;
}

//------------------------------------------------------------------------------