C++ Mathematical Expression Parser Issue - c++

#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include "NodeType.h"
using namespace std;
// Test if token is an operator
bool isOperator(char token);
int getPrecedence(char token);
bool comparePrecedence(char tokenA, char tokenB);
int main()
{
stack<char> tokenStack;
queue<char> tokenQueue;
string expression= "", postfix= "";
char x;
cout<<"Please enter a mathematical expression: "<<endl;
getline(cin, expression);
cout<<expression.length()<<endl;
for(int i = 0; i <= expression.length(); i++)
{
x = expression[i];
if(isdigit(x))
{
tokenQueue.push(x);
}
if(isOperator(x))
{
while((!tokenStack.empty()) && (comparePrecedence(x, tokenStack.top() == true)))
{
char z = tokenStack.top();
tokenQueue.push(z);
tokenStack.pop();
}
tokenStack.push(x);
}
if(x == '(')
{
tokenStack.push(x);
}
if(x == ')')
{
while((!tokenStack.empty()) && (tokenStack.top() != '('))
{
char z = tokenStack.top();
tokenQueue.push(z);
tokenStack.pop();
}
tokenStack.pop();
}
while(!tokenStack.empty())
{
char z = tokenStack.top();
tokenQueue.push(z);
tokenStack.pop();
}
}
return 0;
}
int getPrecedence(char token)
{
if((token == '+') || (token == '-'))
{
return 1;
}
else if((token == '*') || (token == '/'))
{
return 2;
}
else if ((token == '(') || (token == ')'))
return 0;
else
return 99;
}
// Test if token is an operator
bool isOperator(char token)
{
return token == '+' || token == '-' ||
token == '*' || token == '/';
}
bool comparePrecedence(char tokenA, char tokenB)
{
if(getPrecedence(tokenA) < getPrecedence(tokenB))
return true;
else
return false;
}
For some reason I cannot get my code to work correctly. It always throws a
Thread 1: EXC_BAD_ACCESS (code=EXC_1386_GPFLT) error. It is also not correctly placing the '+' sign when I test using a simple string such as: (3+4).
The Queue should look like: 34+ but it hold 3+4. It seems to me that the '+' operator never gets pushed onto the stack. Can anyone please help me find what I should be focussing my attention on?

Debugging code is a valuable skill to learn, it's my opinion that it should form a much more important part of curricula in schools.
For example, if you modify your code to output all the stack and queue operations thus:
int main()
{
stack<char> tokenStack;
queue<char> tokenQueue;
string expression= "", postfix= "";
char x;
cout<<"Please enter a mathematical expression: "<<endl;
getline(cin, expression);
cout<<expression.length()<<endl;
for(int i = 0; i <= expression.length(); i++)
{
x = expression[i];
if(isdigit(x))
{
tokenQueue.push(x);
cout << "qpush A " << x << '\n';
}
if(isOperator(x))
{
while((!tokenStack.empty()) && (comparePrecedence(x, tokenStack.top() == true)))
{
char z = tokenStack.top();
tokenQueue.push(z);
cout << "spop G " << z << '\n';
cout << "qpush B " << z << '\n';
tokenStack.pop();
}
tokenStack.push(x);
cout << "spush E " << x << '\n';
}
if(x == '(')
{
tokenStack.push(x);
cout << "spush F " << x << '\n';
}
if(x == ')')
{
while((!tokenStack.empty()) && (tokenStack.top() != '('))
{
char z = tokenStack.top();
tokenQueue.push(z);
cout << "spop H " << z << '\n';
cout << "qpush C " << z << '\n';
tokenStack.pop();
}
cout << "spop I " << tokenStack.top() << '\n';
tokenStack.pop();
}
while(!tokenStack.empty())
{
char z = tokenStack.top();
tokenQueue.push(z);
cout << "spop J " << z << '\n';
cout << "qpush D " << z << '\n';
tokenStack.pop();
}
}
return 0;
}
and run it with a simple 3+4, you'll see the following output:
qpush A 3
spush E +
spop J +
qpush D +
qpush A 4
So you are placing the operation on the stack. However, you later take it off the stack and put it on the queue before you place the next digit on the queue.
That's definitely the wrong order but, if you examine the code, it's not just a small snippet that has two lines in the wrong order (that would be too easy).
The code that's doing that transfer from stack to queue is the final while loop in main() which, after every single character, transfers all the items from the stack to the queue, effectively rendering your stack superfluous.
That's where you should be looking but I'll give you a clue. You don't want to be transferring stack to queue after every character, only for those that involve numbers.
There may well be other problems after you solve that one but that method (debugging output every time you do something important) should be able to give you enough information to fix whatever comes along.

Related

Why does cin.peek() == '\n' work for '+' and '-', but not for '*', '/', and '^'?

I'm doing a calculator in replit. Why does my cin.peek() == '\n' work when I enter + and - but it doesn't work when I enter *, /, or ^?
#include <iostream>
#include <math.h>
#include <vector>
#include <istream>
using namespace std;
float hasil;
vector<float> num;
vector<char> op;
void calc(float x, float y, char z) {
if (z == '+') {
hasil = x + y;
}
else if (z == '-') {
hasil = x - y;
}
else if (z == '*') {
hasil = x * y;
}
else if (z == '/') {
hasil = x / y;
}
else if (z == '^') {
hasil = pow(x,y);
}
else {
cout<< "wrong operator";
}
}
void input () {
float in;
char ch;
for (int i = 0;;i++) {
if(cin.peek() == '\n') {
break;
}
else if(cin.peek() == '+') {
op.push_back('+');
}
else if(cin.peek() == '-') {
op.push_back('+');
}
else if(cin.peek() == '*') {
op.push_back('*');
}
else if(cin.peek() == '/') {
op.push_back('/');
}
else if(cin.peek() == '^') {
op.push_back('^');
}
cin >> in;
num.push_back(in);
}
for (auto i = num.begin(); i != num.end(); ++i) {
cout << *i << " ";
}
for (auto i = op.begin(); i != op.end(); ++i) { //this is just so I can see what is in the vectors
cout << *i << " ";
}
calc(num.at(0),num.at(1),op.at(0));
for (int i = 2; i < num.size(); i++)
calc(hasil,num.at(i),op.at(i-1));
}
int main() {
cout << "rumus = ";
input();
cout << " = ";
cout << hasil;
}
When I enter 1+2+3+4 it works fine, but the for loop doesn't break when I, for example, enter 1/3 or 2/3.
if(cin.peek() == '\n') {
break;
}
Why doesn't this run when there is a /, *, or ^ in what I enter?
Sorry if I have bad grammar. English is not my first language, and I am very new to C++ and coding in general. I don't know much about coding.
If you enter "4-2", you might notice that the numbers are 4 and -2, and the operator is +.
It produces the correct result by mistake because of if(cin.peek() == '-') { op.push_back('+'). (Copy-paste bug?)
You never actually read an operator, you only read floats.
"+2" and "-2" are valid inputs when reading a number, and peek leaves the character in the stream.
Thus, "1+2" is read as "1" and "+2", "1-2" as "1" and "-2".
None of the other operators can prefix a number, so in all those cases the stream enters an error state, never reads anything, and you're stuck in a loop.
I will leave fixing the bug as an exercise.

How to debug the error message "abort() has been called"?

There is no red line under the code. When I start without debugging, after I entered the email, a failure is popped up, "abort() has been called". How can I debug this?
#include <iostream>
#include <string>
using namespace std;
int main() {
string email;
bool good = false;
while (good == false)
{
there:
cout << "Email is ";
cin.ignore();
getline(cin, email);
cout << email.length();
int a;
for (int q = 0; q <= email.length(); q++)
{
char x = email.at(q);
int count = 0;
while (x == '#')
{
a = 1;
count++;
}
if (count > 1)
{
a = 0;
}
}
if ((email.at(0) == '#') || (email.at(email.length()) == '#') || (a == 0))
{
cout << "Input is invalid. One character ‘#’ must be found. Moreover, there must be some characters before and after the character ‘#’." << endl;
goto there;
}
else
{
good = true;
}
}
}
I see a lot of problems in your code. First check my comment for one about your for-loop.
Next, in your for loop, you while-loop will be an infinite loop if the first character is indeed '#', as you would never break out of it.
while (x == '#')
{
a = 1;
count++;
}

Infix to Postfix to Answer Program (thought process right?)

I'm aware that there's already stuff here regarding this but I'm just posting to check if my logic lines up with my code (if I'm thinking about this whole infix Postfix thing the way I should be).
The code I've seen regarding this topic on this site look a little different from mine. I'm kind of a novice at C++. Anyway, my code so far looks like it is just fine and should work just fine but it's not working the way it should. I've included my thought process as comments in the code below. Please let me know if what I'm thinking is okay.
Here's the code:
#include <iostream>
#include <stack>
#include <sstream>
#include <string>
using namespace std;
int priority (string item)
{
int prior = 0;
if (item == "(")
{
prior = 1;
}
if ((item == "+") || (item == "-"))
{
prior = 2;
}
else if ((item == "*") || (item == "/"))
{
prior = 3;
}
else
{
prior = 4;
}
return prior;
}
int main()
{
stack<string> st;
string output;
cout << "Welcome. This program will calculate any arithmetic expression you enter" << endl;
cout << "Please enter an arithmetic expression below: " << endl;
char line[256];
cin.getline(line, 256);
string exp;
exp = line;
cout << "This is the expression you entered: ";
cout << exp << endl;
string item;
istringstream iss(exp);
iss >> item;
// While there are still items in the expression...
while ( iss )
{
// If the item is a number
if (isdigit('item') == true)
{
output = output + " " + item;
}
// If the stack is empty
else if (st.size() == 0)
{
st.push(item);
}
// If the item is not a number
else if (isdigit('item') == false)
{
// convert that item in the expression to a string
atoi(item.c_str());
int prior1 = 0;
int prior2 = 0;
// If that string is a LEFT PARENTHESIS
if (item == "(")
{
st.push(item);
}
// If that string is a RIGHT PARENTHESIS
else if (item == ")")
{
while ((st.empty() == false) && (st.top() != "("))
{
output = st.top() + " ";
st.pop();
}
st.pop();
}
else
{
// store what is returned from "priority" in "prior1"
prior1 = priority(item);
// pass item on top of the stack through "priority"
// store that in "prior2;
prior2 = priority(st.top());
// while loop here, while item has a higher priority...
// store numbers in a variable
while (prior1 > prior2)
{
output = output + " " + st.top();
st.pop();
prior2 = priority(st.top());
}
}
}
}
while (st.empty() == false)
{
output = st.top() + " ";
st.pop();
}
cout << "Here's the postfix: " << output << endl;
}
This is for evaluating postfix to an actual answer:
// EVALUATE POSTFIX
stack<int> st2;
string output2;
istringstream iss2(exp);
iss2 >> item;
while (iss)
{
// If the item is a number
if (isdigit('item') == true)
{
st.push(item);
}
if (isdigit('item') == false)
{
// store item in a variable
// pop another item off the stack
// store that in a variable.
// apply operator to both.
// push answer to the top of the stack.
int m = 0;
int n = 0;
int total = 0;
m = st2.top();
st2.pop();
n = st2.top();
st2.pop();
if (item == "+")
{
total = m + n;
st2.push(total);
}
else if (item == "-")
{
total = m - n;
st2.push(total);
// add the thing you popped of the stack with the first thing on the stack
}
else if (item == "*")
{
total = m * n;
st2.push(total);
}
else if (item == "/")
{
total = m / n;
st2.push(total);
}
}
}
cout << "Here's your answer: " << st2.top() << endl;
}
Am I thinking about this whole infix-postfix thing the way I should be? Am I on track to solving this problem? My apologies if this question seems simple. I'm kind of a novice at this. Thank you very much.

Writing a Taste test program for C++ not incrementing

I am writing a taste test program for a class and it will run fine up until my if statements. However, once I get into my if statements it isn't incrementing i, so it never leaves the while loop.
#include <iostream>
using namespace std;
void main()
{
int i = 0;
int q = 0;
int p = 0;
int c = 0;
char preference;
int x = 0;
cout << "How many taste tests would you like to do?" << endl;
cin >> x;
while (i<x)
{
cout << "Do you prefer Coke, Pepsi, or are they the same? Use c for coke, p for pepsi, and q for the same\n";
cin >> preference;
if (preference == 'q' || preference == 'Q')
{
q = q + 1;
i++;
}
if (preference == 'p' || preference == 'P')
{
p = p + 1;
i++;
}
if (preference == 'c' || preference == 'C')
{
c = c + 1;
i++;
}
}
if (p>q)
{
cout << "Pepsi wins" << endl;
if (c>p)
cout << "Coke wins" << endl;
if (c == p)
cout << "Tie" << endl;
}
}
I think that you are trying to check if the a determined char was clicked by cin >> preference but you are test int vars, so if i press 'q'
//if(preference==q || preference==Q) // 'q'==0 || 'p'==0
if(preference=='q' || preference=='Q') // 'q'=='q' || 'q'=='Q'
so add ''
I hope this helps
Change the following lines in the code for the expected behavior.
//if(preference==q || preference==Q)
if(preference=='q' || preference=='Q'
//if(preference==p || preference==P)
if(preference=='p' || preference=='P')
//if(preference==c || preference==C)
if(preference=='c' || preference=='C')

String calculator that has no precedence and is left-associative

The code for this string calculator has no operator precedence and I am not too sure how to fix it. I am confident it has something to do with the switch statement but I need this string calculator to move from left to right and calculate no matter if multiplication occurs before subtraction/addition or not. Here is the code so far:
#include<iostream>
#include<sstream>
#include<string>
#include<cctype>
#include<cmath>
using namespace std;
enum {PLUS='+',MINUS='-',MULT='*'};
int numberValue(string &expr)
{
istringstream is(expr);
int value = 0;
is >> value;
return value;
}
int expressionValue(string &expr)
{
int i = 0;
int p = 0;
if(expr.at(0) == '(' && expr.at(expr.length()-1) == ')')
{
for(i=0;i<expr.length();i++)
{
if(expr.at(i)=='(')
p++;
else if(expr.at(i)==')')
p--;
if(p==0)
break;
}
if(i==expr.length()-1)
return expressionValue(expr.substr(1,expr.length()-2));
}
for(i=0;i<expr.length();i++)
{
if(expr.at(i)=='(')
p++;
else if(expr.at(i)==')')
p--;
else if(p==0 && ispunct(expr.at(i)))
{
switch(expr.at(i))
{
case PLUS:
return expressionValue(expr.substr(0,i)) +
expressionValue(expr.substr(i+1,expr.length()-i- 1));
case MINUS:
return expressionValue(expr.substr(0,i)) -
expressionValue(expr.substr(i+1,expr.length()-i-1));
case MULT:
return expressionValue(expr.substr(0,i)) *
expressionValue(expr.substr(i+1,expr.length()-i-1));
}
}
}
return numberValue(expr);
}
bool Validate(string inputStr)
{
for(int x = 0;x < inputStr.length(); x ++)
{
if((inputStr[x] == '+') || (inputStr[x] == '-'))
{
if((inputStr[x+1] == '+') || (inputStr[x+1] =='-'))
{
return false;
}
}
}
string arr = "0123456789+-*";
int count = 0;
for(int a = 0; a < inputStr.length(); a++)
{
for(int b = 0; b < arr.length(); b++)
{
if(inputStr[a] == arr[b])
{
count++;
}
}
}
if(count == inputStr.length())
{
return true;
}
else
{
return false;
}
}
int main()
{
string expressionString;
string retry = "y";
cout << "Enter an expression as a string...you can use addition, subtraction \nand multiplication."<< endl;
cout << "\nKeep in mind that this calculator does not accept decimals and the \nleading operand can not be negative." << endl;
cout << "\nOperands can have no more than 8 digits, each operator has the same \nprecedence, and each operator is left associative." << endl;
do
{
cout << "\nEnter an expression: ";
cin >> expressionString;
if(Validate(expressionString) == true)
{
cout << expressionValue(expressionString) << endl;
}
else
{
cout << "An error has occured in the input" << endl;
}
cout << "Press \"y\" to enter another expression or \"n\" if you want to quit." << endl;
cin >> retry;
}while
(retry == "y");
return 0;
}
I've identified two problems with your code.
First, and easier to fix. Cin >> string will only take everything up to the first whitespace character. It might be worth considering http://www.cplusplus.com/reference/istream/istream/getline/ which will take everything up to the newline character. This will stop your program from just returning '1' if you type '1 + 1'
Your second problem, and the one I think you are more interested in, is the fact that you've accidentally made your operators right-associative. This is a consequence of the way your program is recursing. If you think about the way your function is calling itself for the statement 1 + 2 * 3. When it encounters the first + it calls ExpressionValue('1') + ExpressionValue(2 * 3). Because of this the multiplication will be evaluated before the addition in that case.
The easiest way to solve that problem will probably be to just parse the string backwards, but I suspect that will require changing the code that handles your parentheses quite a bit.
On a somewhat unrelated note. On the style side of things, some of your code was kind of hard to read because you don't indent the interiors of functions.