#define _CRT_SECURE_NO_DEPRECATE #include #include #include #include #include #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; // число уникальных переменных // определение структуры для стека 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* errCode); // функция проверки лексемы на принадлежность к операторам int isOperator(char* str); // функция проверки является ли лексема числом int isNumber(char* str); // функция проверки может ли лексема являться именем переменной int validVarName(char* str); // функция возвращает результат вычислений в случае успеха или код ошибки в случае неудачи double calc(char* str, int* errCode); // функция поиска в строке имен переменных int parsStr(char* str); // функция вывода сообщения об ошибке void printError(int errCode); // функция выводит результат вычислений в случае успеха или текст сообщения об ошибке в случае неудачи int main() { char* valueS = NULL; // указатель на буфер под значение переменной int checkError = 0; // флаг ошибки double result = 0; // результат вычислений int i = 0; // индексная переменная char str[SIZEMAX] = { '\0' }; // буфер под считываемую строку на SIZEMAX символов char* copyStr = NULL; setlocale(LC_ALL, "RUS"); printf("Введите выражение в обратной польской записи\n"); printf("ВВОД: "); gets_s(str, SIZEMAX); // считывание строки на SIZEMAX символов в буфер str copyStr = malloc(strlen(str) + 1); // выделение памяти под копию считанной строки if (copyStr == NULL) // память под копию строки не была выделена { checkError = 5; }//if else { memset(copyStr, '\0', strlen(str) + 1); // заполнение строки под копию символами концпа строки strncpy(copyStr, str, strlen(str)); // копирование строки str в strcopy checkError = parsStr(copyStr); // флаг обработки считанной строки if (checkError == 0) // ошибок не найдено { // считывание значений переменных for (i = 0; i < varCount; i++) { printf("\nВЫВОД: Введите значение переменной %s\n", varList[i]->name); printf("ВВОД: "); valueS = malloc(SIZEMAX); // выделение памяти под значение переменной if (valueS == NULL) // проверка выделения памяти под значение переменной { checkError = 6; break; }//if scanf("%s", valueS); // считывание значения переменной if (isNumber(valueS) == 1) // считанное значение является числом { varList[i]->value = atof(valueS); // запись соответствующего значения переменной в массив переменных }//if else { checkError = 4; // в качестве значения переменной введено не число free(valueS); // очистка памяти для считывания значения переменной break; }//else free(valueS); // очистка памяти для считывания значения переменной }//for if (checkError == 0) // ошибок не найдено { result = calc(str, &checkError); // присвоение результата вычислений if (checkError == 0) // ошибок не выявлено { printf("\nРезультат: %lf\n\n", result); }//if }//if }//if }// else printError(checkError); // вывод сообщения об ошибке clearVariables(); // очистка известных переменных if (copyStr != NULL) // если память под копию выделена { free(copyStr); // очистка памяти под копию считанной строки } system("pause"); return checkError; }//main stack* stackInit() { stack* newStack; // указатель на новый стек newStack = malloc(sizeof(stack)); // выделение памяти под новый стек if (newStack == NULL) // память под стек не была выделена { return newStack; }//if newStack->container = NULL; // инициализация массива стека newStack->size = 0; // инициализация размера стека return newStack; }//stackInits void stackClear(stack** myStack) { free((*myStack)->container); // очистка массива стека free(*myStack); // удаление указателя на стек return; }//stackClear 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; }//if else { (*myStack)->container[(*myStack)->size - 1] = value; // запись нового значения в стек return 0; }//else }//stackPush 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; }//stackPop int createVariable(char* varName) { var* newVar = NULL; // указатель на новую переменную varList = realloc(varList, (varCount + 1) * sizeof(var*)); // выделение дополнительной памяти в массиве переменных под новую переменную if (varList == NULL) // дополнительная память не была выделена { return -1; }//if newVar = malloc(sizeof(var)); // выделение памяти под новую переменную if (newVar == NULL) // дополнительная память не была выделена { return -1; }//if newVar->name = malloc((strlen(varName) + 1) * sizeof(char)); // выделение памяти под имя новой переменной if (newVar->name == NULL) // память под имя новой переменной не была выделена { free(newVar); // очистка памяти под новую переменную return -1; }//if memset(newVar->name, '\0', (strlen(varName) + 1)); memcpy(newVar->name, varName, strlen(varName)); // копирование имени новой переменной в структуру newVar->value = 0.0; // задание начального значения новой переменной varList[varCount] = newVar; // запись новой переменной в массив переменных varCount++; // увеличение счетчика количества переменных на 1 return 0; }//createVariable void clearVariables() { int i = 0; // индексная переменная for (i = 0; i < varCount; i++) { free(varList[i]->name); // очистка памяти под имя переменной free(varList[i]); // очистка памяти под значение переменной }//for varCount = 0; // обнуление счетчика количества переменных return; }//clearVariables double operate(char operator, stack** myStack, int* errCode) { double op2 = stackPop(myStack); double op1 = stackPop(myStack); switch (operator) { case '+': return op1 + op2; case '-': return op1 - op2; case '*': return op1 * op2; case '/': if (op2 == 0) // деление на 0 { *errCode = 3; return; }//if else return op1 / op2; case '^': if (op1 == 0 && op2 < 0) // деление на 0 { *errCode = 3; return; }//if else return powf(op1, op2); }//switch }//operate int isOperator(char* str) { // в лексеме найден символ принадлежащий к списку операторов и длина лексемы 1 return (strpbrk(str, "+-/*^") != NULL && strlen(str) == 1) ? 1 : 0; }//isOperator 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] == '-' && i == 0 && strlen(str) != 1) { continue; }//if else { if (str[i] == ',') // текущий символ - разделитель в вещественном числе { if (foundPoint == 0) // символ разделитель ранее не встречен { foundPoint = 1; // флаг - символ разделитель найден }//if else { return 0; }//else }//if else { return 0; }//else }//else }//if }//for return 1; }// isNumber int validVarName(char* str) { int i = 0; // индексная переменная if (isalpha(str[0]) == 0) // первый символ - не буква { return 0; }//if // проходим по всем элементам лексемы for (i = 1; i < strlen(str); i++) { if (isalnum(str[i]) == 0) // текущий символ - не буква и не число { return 0; }//if }//for return 1; }//validVarName double calc(char* str, int* errCode) { double res = 0.0; // результат вычислений char* tmp = NULL; // указатель на лексему int i = 0; // индексная переменная stack* myStack = stackInit(); // создание стека *errCode = 0; if (myStack == NULL) // память под стек не была выделена { *errCode = 1; // флаг найдена ошибка return res; // код ошибки }//if 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); // запись числа в стек }//if else if (isOperator(tmp) == 1) // лексема - оператор { if (myStack->size >= 2) // в стеке 2 числа или более { stackPush(operate(*tmp, &myStack, errCode), &myStack); // в стек результата операции }//if else { stackClear(&myStack); // очистка стека *errCode = 2; // флаг найдена ошибка return res; // код ошибки }//else }//else if else // встречена переменная { for (i = 0; i < varCount; i++) { // имя переменной в массиве переменных найдено if (strcmp(tmp, varList[i]->name) == 0) { stackPush(varList[i]->value, &myStack); // запись значения переменной в стек }//if }//for }//else tmp = strtok(NULL, "\t "); // переход к следующей лексеме }//while res = stackPop(&myStack); stackClear(&myStack); return res; }//calc int parsStr(char* str) { int operandCount = 0; // число операндов int operateCount = 0; // число операторов 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 if (strcmp(tmp, "PI") == 0) // лексема - число Пи { tmp = strtok(NULL, "\t "); // указатель на следующую лексему operandCount++; // увеличение на 1 счетчика числа операндов continue; }//if if (isOperator(tmp) == 1) // лексема - оператор { operateCount++; // увеличение на 1 счетчика числа операторов }//if if (isNumber(tmp) == 1) // лексема - число { operandCount++; // увеличение на 1 счетчика числа операндов }//if 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 }//for if (knownVariable == 1) { tmp = strtok(NULL, "\t "); // указатель на следующую лексему continue; }//if indicator = createVariable(tmp); // флаг создалась ли переменная: 0 - да, -1 - нет }//if else { indicator = -2; // флаг -2, встречена неизвестная лексема return indicator; }//else }//if tmp = strtok(NULL, "\t "); // указатель на следующую лексему }//while if (operateCount != operandCount - 1) // недостаточное число операторов или операндов { indicator = -3; }//if return indicator; }//parsStr void printError(int errCode) { switch (errCode) { case 0: return; case -1: printf("\nОшибка! Невозможно выделить память\n\n"); return; case -2: printf("\nОшибка! Встречена неизвестная лексема\n\n"); return; case -3: printf("\nОшибка! Недостаточно операторов или операндов\n\n"); return; case 1: printf("\nОшибка! Невозможно выделить память под стек.\n\n"); return; case 2: printf("\nОшибка! Встречен оператор, а количество чисел в стеке меньше двух.\n\n"); return; case 3: printf("\nОшибка! Деление на 0.\n\n"); return; case 4: printf("\nОшибка! Недопустимое значение переменной\n\n"); return; case 5: printf("\nОшибка! Невозможно выделить память под копию строки\n\n"); return; default: printf("\nНеизвестный код ошибки.\n\n"); return; }//switch }//printError