#include <string>
using std::string;
#include <iostream>
#include <memory>
using std::make_shared;
#include "expression_parts.h"
#include "expr_stack.h"
/*
* Class to read the input as a stream of Expression_Part.
*/
class Reader {
public:
// Construct one. If an ostream is given, input is prompted
// for on it.
Reader(std::istream &i, std::ostream *o = NULL):
in(i), out(o), atstart(true) { }
// Read in an item. This performs input, and creates and returns an
// appropriate object. It returns null to indicate the end of the
// the line. If a second pointer (to an ostream) is sent, it is used
// to issue prompts at the start of each line.
std::shared_ptr<Expression_Part> read()
{
// If we're at the start of the line, prompt.
if(atstart) {
if(out) *out << "ecalc> ";
atstart = false;
}
// Clear out leading space, but don't read the non-space which
// terminates it, and don't read past the end of the line. The
// peek() method tells you the next character without consuming
// it. So, the loop reads things so long as they're white
// space.
while(in.peek() == ' ' || in.peek() == '\t')
in.get();
if(in.eof()) return NULL;
// See if we have an operand.
char tocome = in.peek();
if(isdigit(tocome))
return make_shared<Operand>(readint());
// Okay. Read the character and act on it. These are all
// operators, except \n, which sets the start of line flag and
// returns NULL.
tocome = in.get();
while(tocome) {
switch(tocome) {
case '+':
return make_shared<Oper_Plus>();
case '-':
// This is tricky. Could be a negative number,
// but we only count it that way if the very
// next char is a digit.
if(isdigit(in.peek()))
return make_shared<Operand>(-readint());
else
return make_shared<Oper_Minus>();
case '*': return make_shared<Oper_Times>();
case '/': return make_shared<Oper_Div>();
case '%': return make_shared<Oper_Mod>();
case ')': return make_shared<Right>();
case '(': return make_shared<Left>();
case '\n':
atstart = true;
return NULL;
default:
// Bad input.
throw bad_expression("Bad input character '" +
string(1,tocome) + "'.");
}
}
return NULL;
}
// Clear the line.
void clear()
{
if(atstart) return;
char ch;
while(ch = in.get()) if(ch == '\n') break;
atstart = true;
};
// Check for eof.
bool eof() { return in.eof(); }
private:
std::istream ∈ // Reading stream.
std::ostream *out; // Prompting stream (if any).
bool atstart; // At the start of a line.
// Read and return an integer from the stream.
int readint()
{
int n;
in >> n;
return n;
}
};
main()
{
expr_stack s; // Evaluation stack.
Reader in(std::cin, &std::cout);// Prompting reader.
while(true) {
std::shared_ptr<Expression_Part> e;
try {
// Read, finish of finished.
e = in.read();
if(in.eof()) break;
if(e != NULL)
// Perform the action on what we just read.
e->action(s);
else {
// Line done. Complete the expression.
// Apply any remaining operations.
s.reduce();
// Print the result. Stack should contain
// exactly one item, an operand.
if(!s.top()->is_operand())
throw bad_expression("Incomplete expression.");
if(s.size() != 1)
throw bad_expression("Excess symbols.");
std::cout << *s.pop() << std::endl;
}
}
catch(const bad_expression& e) {
// Print the message, clean up, and let the loop
// start again.
std::cout << e.what() << std::endl;
s.clear();
in.clear();
}
}
}