Cod sursa(job #195219)

Utilizator Dr.OptixCristian Dinu Dr.Optix Data 16 iunie 2008 23:23:20
Problema Evaluarea unei expresii Scor 10
Compilator cpp Status done
Runda Arhiva educationala Marime 3.7 kb
/* ========================================================================== */
/*                                                                            */
/*   Evaluarea unei expresii.cpp                                              */
/*   (c) 2008 Dr.Optix (Cristian Dinu)                                        */
/*                                                                            */
/*   This program take an arithmetic  expresion as input from a   file   and  */
/*   return the result. Btw first time i made my own class :D                 */
/* ========================================================================== */

#include <stdlib.h>
#include <stdio.h>

// Error codes
enum EXPR_EVAL_ERR {
	EEE_NO_ERROR = 0,
	EEE_PARENTHESIS = 1,
	EEE_WRONG_CHAR = 2,
	EEE_DIVIDE_BY_ZERO = 3
};

typedef char EVAL_CHAR;

class ExprEval {
private:
	EXPR_EVAL_ERR _err;
	EVAL_CHAR* _err_pos;
	int _paren_count;

	// Parse a number or an expression in parenthesis
	long ParseAtom(EVAL_CHAR*& expr) {
		// Skip spaces
		while(*expr == ' ')
			expr++;

		// Handle the sign before parenthesis (or before number)
		bool negative = false;
		if(*expr == '-') {
			negative = true;
			expr++;
		}
		if(*expr == '+') {
			expr++;
		}

		// Check if there is parenthesis
		if(*expr == '(') {
			expr++;
			_paren_count++;
			double res = ParseSummands(expr);
			if(*expr != ')') {
				// Unmatched opening parenthesis
				_err = EEE_PARENTHESIS;
				_err_pos = expr;
				return 0;
			}
			expr++;
			_paren_count--;
			return negative ? -res : res;
		}

		// It should be a number; convert it to double
		char* end_ptr;
		double res = strtod(expr, &end_ptr);
		if(end_ptr == expr) {
			// Report error
			_err = EEE_WRONG_CHAR;
			_err_pos = expr;
			return 0;
		}
		// Advance the pointer and return the result
		expr = end_ptr;
		return negative ? -res : res;
	}

	// Parse multiplication and division
	long ParseFactors(EVAL_CHAR*& expr) {
		double num1 = ParseAtom(expr);
		for(;;) {
			// Skip spaces
			while(*expr == ' ')
				expr++;
			// Save the operation and position
			EVAL_CHAR op = *expr;
			EVAL_CHAR* pos = expr;
			if(op != '/' && op != '*')
				return num1;
			expr++;
			double num2 = ParseAtom(expr);
			// Perform the saved operation
			if(op == '/') {
				// Handle division by zero
				if(num2 == 0) {
					_err = EEE_DIVIDE_BY_ZERO;
					_err_pos = pos;
					return 0;
				}
				num1 /= num2;
			}
			else
				num1 *= num2;
		}
	}

	// Parse addition and subtraction
	long ParseSummands(EVAL_CHAR*& expr) {
		double num1 = ParseFactors(expr);
		for(;;) {
			// Skip spaces
			while(*expr == ' ')
				expr++;
			EVAL_CHAR op = *expr;
			if(op != '-' && op != '+')
				return num1;
			expr++;
			double num2 = ParseFactors(expr);
			if(op == '-')
				num1 -= num2;
			else
				num1 += num2;
		}
	}

public:
	long Eval(EVAL_CHAR* expr) {
		_paren_count = 0;
		_err = EEE_NO_ERROR;
		double res = ParseSummands(expr);
		// Now, expr should point to '\0', and _paren_count should be zero
		if(_paren_count != 0 || *expr == ')') {
			_err = EEE_PARENTHESIS;
			_err_pos = expr;
			return 0;
		}
		if(*expr != '\0') {
			_err = EEE_WRONG_CHAR;
			_err_pos = expr;
			return 0;
		}
		return res;
	};
	EXPR_EVAL_ERR GetErr() {
		return _err;
	}
	EVAL_CHAR* GetErrPos() {
		return _err_pos;
	}
};


// ============
// Main program
int main() {

		FILE *fin=fopen("evaluare.in","r");
		FILE *fout=fopen("evaluare.out","w");

		static char buff[100001];
		fgets(buff,100001,fin);

		// Evaluate the expression
		ExprEval eval;
		double res = eval.Eval(buff);
		fprintf(fout,"%g",res);

		return 0;
}