/* rcalc.cpp - Rational number calculator Matt Mahoney, mmahoney@cs.fit.edu This program accepts integer expressions from standard input and prints the result as a rational number, e.g. rcalc (run the program) 9/-6 + 1 (input) -1/2 (output) 3/(12-4)*4 (input) 3/2 (output) (input blank line, program exits) Expressions consist of integer numbers, parenthesis, and the operators + - * / on a single line. Spaces are discarded. * and / have higher precedence than + and - unless overridden with parenthesis. Unary - has the highest precedence. Operators of equal precedence are evaluated left to right. Division by 0 or invalid input will result in an error message and resume input. Valid input has the grammar: Expr ::= Term | Expr + Term | Expr - Term Term ::= Factor | Term * Factor | Term / Factor Factor ::= Unsigned | - Factor Unsigned ::= Number | ( Expr ) A Number is a string of 1 or more digits (0-9). The output is a rational number of the form either a or a/b where a and b are integers, b > 1, and gcd(a, b) = 1. */ #include #include #include using namespace std; // Exceptions class DivisionByZero {}; class SyntaxError {}; // A Rational number is the quotient of 2 integers class Rational { int n, d; // n/d such that d > 0 and gcd(n,d) is 1 static int gcd(int, int); // Greatest common divisor public: Rational(int a=0, int b=1); // a/b int num() const {return n;} // numerator, no common factors with denom int denom() const {return d;} // denominator, always > 0 }; // Initialize to a/b removing common factors Rational::Rational(int a, int b) { if (b==0) throw DivisionByZero(); if (b<0) { a=-a; b=-b; } int g=gcd(a, b); n=a/g; d=b/g; } // Greatest common divisor int Rational::gcd(int a, int b) { if (b<0) return gcd(-a, -b); else if (a<0) return gcd(-a, b); else if (a>b) // a, b >= 0 return gcd(b, a); else if (a==0) return b; else return gcd(b%a, a); // b >= a > 0 } // Rational arithmetic Rational operator+(const Rational& a, const Rational& b) { return Rational(a.num()*b.denom()+a.denom()*b.num(), a.denom()*b.denom()); } Rational operator-(const Rational& a, const Rational& b) { return Rational(a.num()*b.denom()-a.denom()*b.num(), a.denom()*b.denom()); } Rational operator*(const Rational& a, const Rational& b) { return Rational(a.num()*b.num(), a.denom()*b.denom()); } Rational operator/(const Rational& a, const Rational& b) { return Rational(a.num()*b.denom(), a.denom()*b.num()); } Rational operator-(const Rational& a) { // unary return Rational(-a.num(), a.denom()); } // Rational comparison bool operator<(const Rational& a, const Rational& b) {return (a-b).num()<0;} bool operator>(const Rational& a, const Rational& b) {return bb);} bool operator>=(const Rational& a, const Rational& b) {return !(ab;} bool operator==(const Rational& a, const Rational& b) {return !(a!=b);} ostream& operator << (ostream& out, const Rational& a) { if (a.denom()==1) out << a.num(); else out << a.num() << "/" << a.denom(); return out; } // Remove spaces from s void trim(string& s) { string r; for (int i=0; i