Пример: Шаблонный класс для вычисления значения выражения, вводимого с клавиатуры

Нижеследующая программа является консольным приложением Windows.

#define _USE_MATH_DEFINES

#include <iostream>

#include <conio.h>

#include <windows.h>

#include <stdio.h>

#include <ctype.h>

#include <string.h>

#include <stdlib.h>

#include <cmath>

using namespace std;

#define NUMVARS 26 // размер массива для хранения значений переменных

template <class PType> class CParser //анализатор

{

//типы элементов выражения:

enum types {DELIMITER = 1, VARIABLE, NUMBER};

//разделитель, переменная, число

// элементы данных класса:

char* exp_ptr; // Указатель на выражение

char token[80]; // Элемент выражения

char tok_type; // Тип элемента

//функции:

int isdelim(char c); // проверяет, является ли элемент разделителем

void get_token(); /* выбирает из строки очередной элемент выражения, помещает его в строку token и определяет его тип */

void putback();//возврат в выражении на 1 элемент назад:

void eval_exp1(PType &result); // присваивание

void eval_exp2(PType &result); // Сложение и вычитание

void eval_exp3(PType &result); // Умножение, деление, остаток от деления

void eval_exp4(PType &result); // Возведение в степень

void eval_exp5(PType &result); // Унарный плюс или минус

void eval_exp6(PType &result); // Обработка выражения в скобках

void atom (PType &result); // Значение числа

void serror(int error); // вывод сообщения об ошибке

PType find_var(char* s); // возвращает значение переменной

public:

CParser(); // конструктор

PType vars[NUMVARS]; // массив значений переменных

PType eval_exp(char *exp); //точка входа

};

//определение функций:

// записываем нули в массив значений переменных:

template <class PType> CParser<PType>::

CParser()

{

exp_ptr = NULL;

for (int i=0; i<NUMVARS; i++)

vars[i]=0;

}

// Функция, проверяющая, является ли элемент разделителем:

template <class PType> int CParser<PType>::

isdelim(char c)

{

if (strchr(" +-/*%^=()",c) || c==9 || c=='\r' || c==0)

return 1;

else return 0;

}

//Функция, которая выбирает из выражения очередной элемент

template <class PType> void CParser<PType>::

get_token()

{

register char *temp = token; //Указатель на token

*temp='\0';

tok_type=0;

if (! *exp_ptr) return; //Конец выражения

while (isspace(*exp_ptr)) ++exp_ptr; // Пропускаем пробелы

if (strchr("+-*/%^=()", *exp_ptr)) // Если очередной символ - знак операции

{

tok_type=DELIMITER;

*temp++ = *exp_ptr++; //Продвигаемся к след. символу

}

else if (isalpha(*exp_ptr))

{

tok_type=VARIABLE;

while (!isdelim(*exp_ptr)) *temp++ = *exp_ptr++;

while (isspace(*exp_ptr)) ++exp_ptr;

//if (*exp_ptr == '(') tok_type=FUNCTION;

}

else if (isdigit(*exp_ptr))

{

tok_type = NUMBER;

while (!isdelim(*exp_ptr)) *temp++ = *exp_ptr++;

}

*temp = '\0';

}

// точка входа в программу разбора выражения:

template <class PType> PType CParser<PType>::

eval_exp(char *exp)

{

PType result;

exp_ptr = exp;

get_token(); // 1 - ый операнд

if (! *token)

{

serror(2); //Нет выражения

return 0;

}

eval_exp1(result);

if(*token) serror(0);

return result;

}

//возврат в выражении на 1 элемент назад:

template <class PType> void CParser<PType>::

putback()

{

char *t = token;

for (; *t; t++) exp_ptr--;

}

//присваивание:

template <class PType> void CParser<PType>::

eval_exp1(PType &result)

{

int slot;

char ttok_type;

char temp_token[80];

if (tok_type == VARIABLE)

{

//сохранить старый элемент:

strcpy(temp_token, token);

ttok_type = tok_type;

//вычисление индекса переменной:

slot = toupper(*token)-'A'; get_token();

if (*token!= '=')

{

putback(); //вернуть текущий элемент

//восстанавливаем предыдущий элемент

strcpy(token, temp_token);

tok_type = ttok_type;

}

else

{

get_token();

eval_exp2(result);

vars[slot] = result;

return;

}

}

eval_exp2(result);

}

// Сложение и вычитание:

template <class PType> void CParser<PType>::

eval_exp2(PType &result)

{

register char op;

PType temp;

eval_exp3(result);

while ((op = *token) == '+' || op == '-')

{

get_token();

eval_exp3(temp);

switch (op)

{

case '+':

result+=temp;

break;

case '-':

result-=temp;

break;

}

}

}

// Умножение, деление, остаток от деления:

template <class PType> void CParser<PType>::

eval_exp3(PType &result)

{

register char op;

PType temp;

eval_exp4(result);

while ((op = *token) == '*' || op == '/' || op == '%')

{

get_token();

eval_exp4(temp);

switch (op)

{

case '*':

result*=temp;

break;

case '/':

result/=temp;

break;

case '%':

result=(int)result % (int) temp;

break;

}

}

}

// Возведение в степень:

template <class PType>void CParser<PType>::

eval_exp4(PType &result)

{

PType temp;

eval_exp5(result);

if (*token == '^')

{

get_token();

eval_exp4(temp);

result=pow(result,temp);

}

}

// Унарный плюс или минус:

template <class PType>void CParser<PType>::

eval_exp5(PType &result)

{

register char op;

op=0;

if ((tok_type == DELIMITER) && *token == '+'

|| *token == '-')

{

op= *token;

get_token();

}

eval_exp6(result);

if (op == '-') result = -result;

}

// Обработка выражения в скобках:

template <class PType>void CParser<PType>::

eval_exp6(PType &result)

{

if (*token == '(')

{

get_token();

eval_exp1(result); // вычисляем выражение в скобках

if (*token!= ')')

serror(1);

get_token();

}

else atom(result);

}

// Значение числа:

template <class PType>void CParser<PType>::

atom (PType &result)

{

switch (tok_type)

{

case NUMBER:

result = atof(token);

get_token(); return;

case VARIABLE:

result = find_var(token);

get_token(); return;

default: serror(0);

}

}

// вывод сообщения об ошибке:

template <class PType>void CParser<PType>::

serror(int error)

{

static char *e[]=

{

"Синтаксическая ошибка",

"Незакрытые скобки",

"Выражение записано неверно"

};

cout << e[error] << endl;

}

// возвращает значение переменной:

template <class PType>PType CParser<PType>::

find_var(char* s)

{

if (!isalpha(*s))

{

serror(1);

return 0;

}

int i=toupper(*token) - 'A';

return vars[i];

}

// файл “Calculator.cpp”:

/*#include <iostream>

#include <conio.h>

#include <windows.h>*/

#include "calculator.h"

//using namespace std;

int main()

{

//Настройки шрифтов и региональных стандартов:

if(SetConsoleCP(1251)==0)

//проверка правильности установки кодировки символов для ввода

{

cerr<<"Fialed to set codepage!"<<endl;

/* если не удалось установить кодовую страницу, вывод сообщения об ошибке */

}

if(SetConsoleOutputCP(1251)==0)//тоже самое для вывода

{

cerr<<"Failed to set OUTPUT page!"<<endl;

}

CParser <double> ob;

char expstr[81];

cout<<" Для выхода из программы введите пустое выражение (нажмите <Enter>)\n";

while(1)

{

cout<<"Введите выражение ";

cin.getline(expstr, 80);

if (expstr[0] == 0) break;

cout<<"Результат = ";

cout<<ob.eval_exp(expstr) << endl;

}

_getch();

return 0;

}

Запустите программу (<Ctrl>+<F5>) и введите несколько выражений, например:

x = -2.5

3 * (x – 1.5^2)

Убедитесь в правильности работы программы.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: