1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
/*
* File: LALR_Calculator.cpp
* Author: Ties
*
* Created on 7 december 2011, 20:01
*/
#include <iostream>
#include <deque>
#include <cmath> // Contains: double pow(double,double)
/*
Error checks:
ERROR: EMPTY DATA STRING (in preprocesser)
ERROR: UNMATCHED (begin) PARENTHESIS (in lexer)
*/
using namespace std;
struct data {
data() : char_count(0), priority_count(0), max_priority(0) {}
deque<float> value;
deque<int> priority;
deque<bool> is_operator;
int char_count;
int priority_count;
int max_priority;
};
int preprocesser(string& s) {
int found = s.find(" "); // Find the first space
while(found!=string::npos) // While there are spaces
{
s.erase(s.begin()+found); // Remove the space
found = s.find(" "); // Find next space
}
return bool(s.size());
}
int lexer(string& s, data& d) {
while(s.size()) // While we still have unprocessed text
{
while(s.size() && s[0]=='(')
{
d.priority_count += 3;
s.erase(0,1);
}
bool sign = (s[0]!='-'); // If the current strings with '-', negate the next value.
if (!sign) s.erase(0,1); // If there was a '-', remove it.
unsigned pos = s.find_first_of("+-*/%^()"); // Find the first operator and check it's position
if (pos == string::npos) pos = s.size(); // If there is no next operator, set the position at the end of the string
d.value.push_back( (2*sign - 1) * atof(s.substr(0,pos).c_str())); // Push the value (possibly negated)
d.priority.push_back(d.priority_count); // Push 0 as the priority
d.is_operator.push_back(false); // Push false, since this is a number
s.erase(0, pos); // Erase the number we just added
while(s.size() && s[0]==')')
{
d.priority_count -= 3;
s.erase(0,1);
if (d.priority_count < 0) return 0; // ERROR: UNMATCHED PARENTHESIS
}
if(s.size()) // While we still have unprocessed text
{
d.value.push_back(s[0]); // Push the operator
d.priority.push_back(d.priority_count); // Push 0 as the priority
d.is_operator.push_back(true); // Push true, since this is an operator
s.erase(0,1); // Erase the operator we just added
}
}
return 1;
}
int parser(data& d) {
for(size_t i = 1; i<d.value.size(); i+=2) // Determine priority of operators and operands
{
unsigned prior = ((d.value[i]=='*' || d.value[i]=='/' || d.value[i]=='%')?1:((d.value[i]=='^')?2:0));
if(d.priority[i-1]==d.priority[i]) d.priority[i-1]+=prior;
if(d.priority[i+1]==d.priority[i]) d.priority[i+1]+=prior;
d.priority[i]+=prior;
}
while(d.value.size()>1)
{
d.max_priority = 0;
for(size_t i = 0; i<d.value.size(); i++) if(d.priority[i]>d.max_priority) d.max_priority = d.priority[i];
for(size_t i = 0; i<d.value.size(); i++)
{
if((d.priority[i]==d.max_priority) && (((i==0) || (d.priority[i-1]<d.max_priority)) && ((i==d.value.size()-1) || (d.priority[i+1]<d.max_priority)))) {d.priority[i]-=1;}
}
for(size_t i = 0; i<d.value.size(); i++)
{
if(d.priority[i]==d.max_priority && d.priority[i+1]==d.max_priority)
{
if (d.value[i+1] == '+') d.value[i] += d.value[i+2];
else if (d.value[i+1] == '-') d.value[i] -= d.value[i+2];
else if (d.value[i+1] == '*') d.value[i] *= d.value[i+2];
else if (d.value[i+1] == '/') d.value[i] /= d.value[i+2];
else if (d.value[i+1] == '%') d.value[i] = int(d.value[i])%int(d.value[i+2]);
else if (d.value[i+1] == '^') d.value[i] = pow(d.value[i], d.value[i+2]);
else continue;
d.value.erase(d.value.begin()+i+1);
d.value.erase(d.value.begin()+i+1);
d.priority.erase(d.priority.begin()+i+1);
d.priority.erase(d.priority.begin()+i+1);
d.is_operator.erase(d.is_operator.begin()+i+1);
d.is_operator.erase(d.is_operator.begin()+i+1);
}
}
}
return 1;
}
int main() {
while(true) {
data processed;
string expression;
getline(cin, expression);
if(preprocesser(expression) && lexer(expression, processed) && parser(processed)) cout << processed.value.front();
cout << endl << endl;
}
return 0;
}
|