Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define _CRT_SECURE_NO_DEPRECATE
- #include <locale.h>
- #include <math.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #define SIZEMAX 256
- #define EXP "2,7182818"
- #define PI "3,1415926"
- // определение структуры для переменных
- struct _var
- {
- char* name; // имя переменной
- double value; // значение переменной
- };
- // определение имени var для типа _var
- typedef struct _var var;
- var** varList = NULL; // двойной указатель на массив переменных
- int varCount = 0; // число уникальных переменных
- int operandCount = 0; // число операндов
- int operateCount = 0; // число операторов
- int errCalc = 0; // флаг ошибки при вычислении
- // определение структуры для стека
- struct _stack
- {
- double* container; // массив значений
- int size; // размер стека
- };
- // определение имени stack для типа _stack
- typedef struct _stack stack;
- // функция выделения памяти под стек
- stack* stackInit();
- // функция очистки стека
- void stackClear(stack** myStack);
- //функция записи значения в стек
- int stackPush(double value, stack** myStack);
- // функция вывода элемента из стека
- double stackPop(stack** myStack);
- // функция создания новой переменной
- int createVariable(char* varName);
- // функция очистки перемнных
- void clearVariables();
- // функция выполнения математических операций
- double operate(char operator, stack** myStack);
- // функция проверки лексемы на принадлежность к операторам
- int isOperator(char* str);
- // функция проверки является ли лексема числом
- int isNumber(char* str);
- // функция проверки может ли лексема являться именем переменной
- int validVarName(char* str);
- // функция возвращает результат вычислений в случае успеха или код ошибки в случае неудачи
- double calc(char* str);
- // функция поиска в строке имен переменных
- int parsStr(char* str);
- // функция выводит результат вычислений в случае успеха или текст сообщения об ошибке в случае неудачи
- int main()
- {
- char* valueS = NULL; // указатель на буффер под значение переменной
- int checkS; // флаг обработки строки
- double checkCalc = 0; // перемнная для проверки результатов вычисления
- int i = 0; // индексная переменная
- char str[SIZEMAX] = { '\0' }; // буфер под считываемую строку на SIZEMAX символов
- setlocale(LC_ALL, "RUS");
- printf("Введите выражение в обратной польской записи\n");
- printf("ВВОД: ");
- gets_s(str, SIZEMAX); // считывание строки на SIZEMAX символов в буфер str
- char* copyStr = malloc(strlen(str) + 1); // выделение памяти под копию считанной строки
- if (copyStr == NULL) // неудалось выделить память
- {
- printf("О\nшибка! Невозможно выделить память\n\n");
- system("pause");
- return 0;
- }
- memset(copyStr, '\0', strlen(str) + 1);
- strncpy(copyStr, str, strlen(str)); // копирование строки str в strcopy
- checkS = parsStr(copyStr); // флаг обработки считанной строки
- if (checkS == 1) // невозможно выделить память
- {
- printf("\nОшибка! Невозможно выделить память\n\n");
- system("pause");
- clearVariables(); // очистка известных переменных
- free(copyStr); // очистка памяти под копию считанной строки
- return 0;
- }
- if (checkS == -1) // встречена неизвестная лексема
- {
- printf("\nОшибка! Встречена неизвестная лексема\n\n");
- system("pause");
- clearVariables(); // очистка известных переменных
- free(copyStr); // очистка памяти под копию считанной строки
- return 0;
- }
- if (operateCount != operandCount - 1) // недостаточное число операторов
- {
- printf("\nОшибка! Недостаточно операторов\n\n");
- system("pause");
- clearVariables(); // очистка известных переменных
- free(copyStr); // очистка памяти под копию считанной строки
- return 0;
- }
- if (checkS == 0) // штатная работа
- {
- // считывание значений переменных
- for (i = 0; i < varCount; i++)
- {
- printf("\nВЫВОД: Введите значение переменной %s\n", varList[i]->name);
- printf("ВВОД: ");
- valueS = malloc(SIZEMAX); // выделение памяти под значение переменной
- scanf("%s", valueS); // считывание значения переменной
- if (isNumber(valueS) == 1) // считанное значение является числом
- {
- varList[i]->value = atof(valueS);
- }
- else
- {
- printf("Ошибка! Недопустимое значение переменной\n\n");
- clearVariables(); // очистка известных переменных
- free(copyStr); // очистка памяти под копию считанной строки
- return 0;
- }
- free(valueS); // очистка памяти для считывания значения переменной
- }
- checkCalc = calc(str);
- if (errCalc == 0) // ошибок не выявлено
- {
- printf("\nРезультат: %lf\n\n", checkCalc);
- }
- else
- {
- // выод сообщения об ошибке в соответствии с ее кодом
- switch ((int)checkCalc)
- {
- case 1:
- printf("\nОшибка! Невозможно выделить память под стек.\n\n");
- break;
- case 2:
- printf("\nОшибка! Встречен оператор, а количество чисел в стеке меньше двух.\n\n");
- break;
- default:
- printf("\nНеизвестный код ошибки.\n\n");
- break;
- }
- }
- }
- clearVariables(); // очистка известных переменных
- free(copyStr); // очистка памяти под копию считанной строки
- system("pause");
- return 0;
- }
- stack* stackInit()
- {
- stack* newStack; // указатель на новый стек
- newStack = malloc(sizeof(stack)); // выделение памяти под новый стек
- if (newStack == NULL) // память под стек не была выделена
- {
- return newStack;
- }
- newStack->container = NULL; // инициализация массива стека
- newStack->size = 0; // инициализация размера стека
- return newStack;
- }
- void stackClear(stack** myStack)
- {
- free((*myStack)->container); // очистка массива стека
- free(*myStack); // удаление указателя на стек
- return;
- }
- int stackPush(double value, stack** myStack)
- {
- (*myStack)->size += 1; // увеличение размера стека на 1
- (*myStack)->container = realloc((*myStack)->container, sizeof(double) * (*myStack)->size); // выделение памяти под новый элемент стека
- if ((*myStack)->container == NULL) // память не была выделена
- {
- return -1;
- }
- else
- {
- (*myStack)->container[(*myStack)->size - 1] = value; // запись нового значения в стек
- return 0;
- }
- }
- double stackPop(stack** myStack)
- {
- double res = 0;
- res = (*myStack)->container[(*myStack)->size - 1]; // присвоение res последнего значения из стека
- (*myStack)->size -= 1; // уменьшени размера стека на 1
- (*myStack)->container = realloc((*myStack)->container, sizeof(double) * (*myStack)->size); // уменьшение выделенной памяти под стек
- return res;
- }
- int createVariable(char* varName)
- {
- var* newVar = NULL; // указатель на новую переменную
- varList = realloc(varList, (varCount + 1) * sizeof(var*)); // выделение дополнительной памяти в массиве переменных под новую переменную
- if (varList == NULL) // дополнительная память не была выделена
- {
- return 1;
- }
- newVar = malloc(sizeof(var)); // выделение памяти под новую переменную
- if (newVar == NULL) // дополнительная память не была выделена
- {
- return 1;
- }
- newVar->name = malloc((strlen(varName) + 1) * sizeof(char)); // выделение памяти под имя новой переменной
- if (newVar->name == NULL) // память под имя новой переменной не была выделена
- {
- free(newVar); // очистка памяти под новую переменную
- return 1;
- }
- memset(newVar->name, '\0', (strlen(varName) + 1));
- memcpy(newVar->name, varName, strlen(varName)); // копирование имени новой переменной в структуру
- newVar->value = 0.0; // задание начального значения новой переменной
- varList[varCount] = newVar; // запись новой переменной в массив переменных
- varCount++; // увеличение счетчика количества переменных на 1
- return 0;
- }
- void clearVariables()
- {
- int i = 0; // индексная переменная
- for (i = 0; i < varCount; i++)
- {
- free(varList[i]->name); // очистка памяти под имя переменной
- free(varList[i]); // очистка памяти под значение переменной
- }
- varCount = 0; // обнуление счетчика количества переменных
- return;
- }
- double operate(char operator, stack** myStack)
- {
- double op2 = stackPop(myStack);
- double op1 = stackPop(myStack);
- switch (operator)
- {
- case '+':
- return op1 + op2;
- case '-':
- return op1 - op2;
- case '*':
- return op1 * op2;
- case '/':
- return op1 / op2;
- case '^':
- return powf(op1, op2);
- }
- }
- int isOperator(char* str)
- {
- // в лексеме найден символ принадлежащий к списку операторов и длига лексемы 1
- if (strpbrk(str, "+-/*^") != NULL && strlen(str) == 1)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- int isNumber(char* str)
- {
- int i = 0; // индексная переменная
- int foundPoint = 0; // флаг найден ли символ разделитель в вещественном числе
- // проходим по всем символам лексемы
- for (i = 0; i < strlen(str); i++)
- {
- if (isdigit(str[i]) == 0) // текущий символ не число
- {
- if (str[i] == ',') // текущий символ - разделитель в вещественном числе
- {
- if (foundPoint == 0) // символ разделитель ранее не встречен
- {
- foundPoint = 1; // флаг - символ разделитель найден
- }
- else
- {
- return 0;
- }
- }
- else
- {
- return 0;
- }
- }
- }
- return 1;
- }
- int validVarName(char* str)
- {
- int i = 0; // индексная переменная
- if (isalpha(str[0]) == 0) // первый символ - не буква
- {
- return 0;
- }
- // проходим по всем элементам лексемы
- for (i = 1; i < strlen(str); i++)
- {
- if (isalnum(str[i]) == 0) // текущий символ - не буква и не число
- {
- return 0;
- }
- }
- return 1;
- }
- double calc(char* str)
- {
- double res = 0; // результат вычислений
- char* tmp = NULL; // указатель на лексему
- int i = 0; // индексная переменная
- stack* myStack = stackInit(); // создание стека
- if (myStack == NULL) // память под стек не была выделена
- {
- errCalc = 1; // флаг найдена ошибка
- return 1.0; // код ошибки
- }
- tmp = strtok(str, "\t "); // считывание лексемы
- while (tmp != NULL) // найдена лексема
- {
- if (strcmp(tmp, "EXP") == 0) tmp = EXP;
- if (strcmp(tmp, "PI") == 0) tmp = PI;
- if (isNumber(tmp) == 1) // лексема - число
- {
- stackPush(atof(tmp), &myStack); // запись числа в стек
- }
- else if (isOperator(tmp) == 1) // лексема - оператор
- {
- if (myStack->size >= 2) // в стеке 2 числа или более
- {
- stackPush(operate(*tmp, &myStack), &myStack); // в стек результата операции
- }
- else
- {
- stackClear(&myStack); // очистка стека
- errCalc = 1; // флаг найдена ошибка
- return 2.0; // код ошибки
- }
- }
- else // встречена переменная
- {
- for (i = 0; i < varCount; i++)
- {
- // имя переменной в массиве переменных найдено
- if (strcmp(tmp, varList[i]->name) == 0)
- {
- stackPush(varList[i]->value, &myStack); // запись значения переменной в стек
- }
- }
- }
- tmp = strtok(NULL, "\t "); // переход к следующей лексеме
- }
- res = stackPop(&myStack);
- stackClear(&myStack);
- return res;
- }
- int parsStr(char* str)
- {
- char* tmp = NULL; // указатель на лексему
- int i = 0; // индексная переменная
- int indicator = 0; // код завершения функции
- int knownVariable = 0; // флаг уникальности переменной
- tmp = strtok(str, "\t "); // считывание лексемы
- while (tmp != NULL)
- {
- knownVariable = 0;
- if (strcmp(tmp, "EXP") == 0) // лексема - экспонента
- {
- tmp = strtok(NULL, "\t "); // указатель на следующую лексему
- operandCount++; // увеличение на 1 счетчика числа операндов
- continue;
- }
- if (strcmp(tmp, "PI") == 0) // лексема - число Пи
- {
- tmp = strtok(NULL, "\t "); // указатель на следующую лексему
- operandCount++; // увеличение на 1 счетчика числа операндов
- continue;
- }
- if (isOperator(tmp) == 1) // лексема - оператор
- {
- operateCount++; // увеличение на 1 счетчика числа операторов
- }
- if (isNumber(tmp) == 1) // лексема - число
- {
- operandCount++; // увеличение на 1 счетчика числа операндов
- }
- if (isNumber(tmp) == 0 && isOperator(tmp) == 0) // лексема - не число и не оператор
- {
- if (validVarName(tmp) == 1) // может ли лексема являться именем переменной
- {
- operandCount++; // увеличение на 1 счетчика числа операндов
- // проверка имени переменной на уникальность
- for (i = 0; i < varCount; i++)
- {
- if (strcmp(tmp, varList[i]->name) == 0) // переменная не уникальна
- {
- knownVariable = 1;
- break;
- }
- }
- if (knownVariable == 1)
- {
- tmp = strtok(NULL, "\t "); // указатель на следующую лексему
- continue;
- }
- indicator = createVariable(tmp); // флаг создалась ли переменная: 0 - да, 1 - нет
- }
- else
- {
- indicator = -1; // флаг -1, встречена неизвестная лексема
- }
- }
- tmp = strtok(NULL, "\t "); // указатель на следующую лексему
- }
- return indicator;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement