baadgeorge

kr

Dec 23rd, 2020 (edited)
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 19.83 KB | None | 0 0
  1. #define _CRT_SECURE_NO_DEPRECATE
  2.  
  3. #include <locale.h>
  4. #include <math.h>
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <string.h>
  8.  
  9. #define SIZEMAX 256
  10. #define EXP "2,7182818"
  11. #define PI  "3,1415926"
  12.  
  13. // определение структуры для переменных
  14. struct _var
  15. {
  16.     char* name; // имя переменной
  17.     double value; // значение переменной
  18. };
  19.  
  20. // определение имени var для типа _var
  21. typedef struct _var var;
  22.  
  23.  
  24. // определение структуры для стека
  25. struct _stack
  26. {
  27.     double* container; // массив значений
  28.     int size; // размер стека
  29. };
  30.  
  31. // определение имени stack для типа _stack
  32. typedef struct _stack stack;
  33.  
  34.  
  35. // функция выделения памяти под стек
  36. stack* stackInit();
  37.  
  38. // функция очистки стека
  39. void stackClear(stack** myStack);
  40.  
  41. //функция записи значения в стек
  42. int stackPush(double value, stack** myStack);
  43.  
  44. // функция вывода элемента из стека
  45. double stackPop(stack** myStack);
  46.  
  47. // функция создания новой переменной
  48. int createVariable(char* varName, var*** varList, int* varCount);
  49.  
  50. // функция очистки переменных
  51. void clearVariables(var*** varList, int* varCount);
  52.  
  53. // функция выполнения математических операций
  54. double operate(char operator, stack** myStack, int* errCode);
  55.  
  56. // функция проверки лексемы на принадлежность к операторам
  57. int isOperator(char* str);
  58.  
  59. // функция проверки является ли лексема числом
  60. int isNumber(char* str);
  61.  
  62. // функция проверки может ли лексема являться именем переменной
  63. int validVarName(char* str);
  64.  
  65. // функция возвращает результат вычислений в случае успеха или код ошибки в случае неудачи
  66. double calc(char* str, int* errCode, var*** varList, int* varCount);
  67.  
  68. // функция поиска в строке имен переменных
  69. int parsStr(char* str, var*** varList, int* varCount);
  70. // функция вывода сообщения об ошибке
  71. void printError(int errCode);
  72.  
  73. // функция выводит результат вычислений в случае успеха или текст сообщения об ошибке в случае неудачи
  74. int main()
  75. {
  76.     var** varList = NULL; // двойной указатель на массив переменных
  77.     int varCount = 0; // число уникальных переменных
  78.  
  79.     char* valueS = NULL; // указатель на буффер под значение переменной
  80.     int checkError = 0; // флаг ошибки
  81.     double result = 0; // результат вычислений
  82.     int i = 0; // индексная переменная
  83.     char str[SIZEMAX]; // буфер под считываемую строку на SIZEMAX символов
  84.     char* copyStr = NULL;
  85.  
  86.     setlocale(LC_ALL, "RUS");
  87.     printf("Введите выражение в обратной польской записи\n");
  88.     printf("ВВОД: ");
  89.     gets_s(str, SIZEMAX);  // считывание строки на SIZEMAX символов в буфер str
  90.  
  91.     copyStr = malloc(strlen(str) + 1); // выделение памяти под копию считанной строки
  92.  
  93.     if (copyStr == NULL) // память под копию строки не была выделена
  94.     {
  95.         checkError = 5;
  96.     }//if
  97.     else
  98.     {
  99.        
  100.         strcpy(copyStr, str); // копирование строки str в strcopy
  101.  
  102.         checkError = parsStr(copyStr, &varList, &varCount); // функция находит имена переменных в строке и возвращает флаг ошибки
  103.  
  104.         if (checkError == 0) // ошибок не найдено
  105.         {
  106.             // считывание значений переменных
  107.             for (i = 0; i < varCount; i++)
  108.             {
  109.                 printf("\nВЫВОД: Введите значение переменной %s\n", varList[i]->name);
  110.                 printf("ВВОД: ");
  111.                 valueS = malloc(SIZEMAX); // выделение памяти под значение переменной
  112.  
  113.                 if (valueS == NULL) // проверка выделения памяти под значение переменной
  114.                 {
  115.                     checkError = -1;
  116.                     break;
  117.                 }//if
  118.                 scanf("%s", valueS); // считывание значения переменной
  119.  
  120.                 if (isNumber(valueS) == 1) // считанное значение является числом
  121.                 {
  122.                     varList[i]->value = atof(valueS); // запись соответствующего значения переменной в масссив переменных
  123.                 }//if
  124.                 else
  125.                 {
  126.                     free(valueS); // очистка памяти для считывания значения переменной
  127.                     checkError = 4; // в качестве значения переменной введено не число
  128.                     break;
  129.                 }//else
  130.                 free(valueS); // очистка памяти для считывания значения переменной
  131.             }//for
  132.  
  133.             if (checkError == 0) // ошибок не найдено
  134.             {
  135.                 result = calc(str, &checkError, &varList, &varCount); // присвоение результата вычислений
  136.  
  137.                 if (checkError == 0) // ошибок не выявлено
  138.                 {
  139.                     printf("\nРезультат: %lf\n\n", result);
  140.                 }//if
  141.             }//if
  142.         }//if
  143.     }// else
  144.  
  145.     printError(checkError); // вывод сообщения об ошибке
  146.     clearVariables(&varList, &varCount); // очистка известных переменных
  147.     if (copyStr != NULL) // если память под копию выделена
  148.     {
  149.         free(copyStr); // очистка памяти под копию считанной строки
  150.     }
  151.     system("pause");
  152.     return checkError;
  153. }//main
  154.  
  155. stack* stackInit()
  156. {
  157.     stack* newStack; // указатель на новый стек
  158.     newStack = malloc(sizeof(stack)); // выделение памяти под новый стек
  159.     if (newStack == NULL) // память под стек не была выделена
  160.     {
  161.         return newStack;
  162.     }//if
  163.     newStack->container = NULL; // инициализация массива стека
  164.     newStack->size = 0; // инициализация размера стека
  165.     return newStack;
  166. }//stackInits
  167.  
  168. void stackClear(stack** myStack)
  169. {
  170.     free((*myStack)->container); // очистка массива стека
  171.     free(*myStack); // удаление указателя на стек
  172.     return;
  173. }//stackClear
  174.  
  175. int stackPush(double value, stack** myStack)
  176. {
  177.     (*myStack)->size += 1; // увеличение размера стека на 1
  178.     (*myStack)->container = realloc((*myStack)->container, sizeof(double) * (*myStack)->size); // выделение памяти под новый элемент стека
  179.     if ((*myStack)->container == NULL) // память не была выделена
  180.     {
  181.         return -1;
  182.     }//if
  183.     else
  184.     {
  185.         (*myStack)->container[(*myStack)->size - 1] = value; // запись нового значения в стек
  186.         return 0;
  187.     }//else
  188. }//stackPush
  189.  
  190. double stackPop(stack** myStack)
  191. {
  192.     double res = 0;
  193.     res = (*myStack)->container[(*myStack)->size - 1]; // присвоение res последнего значения из стека
  194.     (*myStack)->size -= 1; // уменьшени размера стека на 1
  195.     (*myStack)->container = realloc((*myStack)->container, sizeof(double) * (*myStack)->size); // уменьшение выделенной памяти под стек
  196.     return res;
  197. }//stackPop
  198.  
  199. int createVariable(char* varName, var*** varList, int* varCount)
  200. {
  201.     var* newVar = NULL; // указатель на новую переменную
  202.  
  203.     *varList = realloc(*varList, (*varCount + 1) * sizeof(var*)); // выделение дополнительной памяти в массиве переменных под новую переменную
  204.     if (*varList == NULL) // дополнительная память не была выделена
  205.     {
  206.         return -1;
  207.     }//if
  208.  
  209.     newVar = malloc(sizeof(var)); // выделение памяти под новую переменную
  210.     if (newVar == NULL) // дополнительная память не была выделена
  211.     {
  212.         return -1;
  213.     }//if
  214.  
  215.     newVar->name = malloc((strlen(varName) + 1) * sizeof(char)); // выделение памяти под имя новой переменной
  216.     if (newVar->name == NULL) // память под имя новой переменной не была выделена
  217.     {
  218.         free(newVar); // очистка памяти под новую переменную
  219.         return -1;
  220.     }//if
  221.  
  222.     memset(newVar->name, '\0', (strlen(varName) + 1)); // можно использовать strcat, strncat
  223.     memcpy(newVar->name, varName, strlen(varName)); // копирование имени новой переменной в структуру
  224.     newVar->value = 0.0; // задание начального значения новой переменной
  225.  
  226.     (*varList)[*varCount] = newVar; // запись новой переменной в массив переменных
  227.  
  228.     (*varCount)++; // увеличение счетчика количества переменных на 1
  229.     return 0;
  230. }//createVariable
  231.  
  232. void clearVariables(var ***varList, int *varCount)
  233. {
  234.     int i; // индексная переменная
  235.  
  236.     for (i = 0; i < *varCount; i++)
  237.     {
  238.         free((*varList)[i]->name); // очистка памяти под имя переменной
  239.         free((*varList)[i]); // очистка памяти под значение  переменной
  240.     }//for
  241.  
  242.     varCount = 0; // обнуление счетчика количества переменных
  243.     return;
  244. }//clearVariables
  245.  
  246. double operate(char operator, stack** myStack, int* errCode)
  247. {
  248.     double op2 = stackPop(myStack);
  249.     double op1 = stackPop(myStack);
  250.    
  251.     switch (operator)
  252.     {
  253.     case '+':
  254.         return op1 + op2;
  255.     case '-':
  256.         return op1 - op2;
  257.     case '*':
  258.         return op1 * op2;
  259.     case '/':
  260.         if (op2 == 0) // деление на 0
  261.         {
  262.             *errCode = 3;
  263.             return;
  264.         }//if
  265.         else return op1 / op2;
  266.     case '^':
  267.         if (op1 == 0 && op2 < 0) // деление на 0
  268.         {
  269.             *errCode = 3;
  270.             return;
  271.         }//if
  272.         else return pow(op1, op2);
  273.     }//switch
  274. }//operate
  275.  
  276. int isOperator(char* str)
  277. {
  278.     // в лексеме найден символ принадлежащий к списку операторов и длина лексемы 1
  279.     return (strpbrk(str, "+-/*^") != NULL && strlen(str) == 1) ? 1 : 0;
  280. }//isOperator
  281.  
  282. int isNumber(char* str)
  283. {
  284.     int i; // индексная переменная
  285.     int foundPoint = 0; // флаг найден ли символ разделитель в вещественном числе
  286.  
  287.     // проходим по всем символам лексемы
  288.     for (i = 0; i < strlen(str); i++)
  289.     {
  290.         if (isdigit(str[i]) == 0) // текущий символ не число
  291.         {
  292.             if (str[i] == '-' && i == 0 && strlen(str) != 1)
  293.             {
  294.                 continue;
  295.             }//if
  296.             else
  297.             {
  298.                 if (str[i] == ',') // текущий символ - разделитель в вещественном числе
  299.                 {
  300.                     if (foundPoint == 0) // символ разделитель ранее не встречен
  301.                     {
  302.                         foundPoint = 1; // флаг - символ разделитель найден
  303.                     }//if
  304.                     else
  305.                     {
  306.                         return 0;
  307.                     }//else
  308.                 }//if
  309.                 else
  310.                 {
  311.                     return 0;
  312.                 }//else
  313.             }//else
  314.            
  315.         }//if
  316.     }//for
  317.     return 1;
  318. }// isNumber
  319.  
  320. int validVarName(char* str)
  321. {
  322.     int i; // индексная переменная
  323.  
  324.     if (isalpha(str[0]) == 0) // первый символ - не буква
  325.     {
  326.         return 0;
  327.     }//if
  328.  
  329.     // проходим по всем элементам лексемы
  330.     for (i = 1; i < strlen(str); i++)
  331.     {
  332.         if (isalnum(str[i]) == 0) // текущий символ - не буква и не число
  333.         {
  334.             return 0;
  335.         }//if
  336.     }//for
  337.  
  338.     return 1;
  339. }//validVarName
  340.  
  341. double calc(char* str, int* errCode, var ***varList, int *varCount)
  342. {
  343.     double res = 0.0; // результат вычислений
  344.     char* tmp = NULL; // указатель на лексему
  345.     int i; // индексная переменная
  346.     stack* myStack = stackInit(); // создание стека
  347.  
  348.     if (myStack == NULL) // память под стек не была выделена
  349.     {
  350.         *errCode = 1;
  351.         return res;
  352.     }//if
  353.  
  354.     tmp = strtok(str, "\t "); // считывание лексемы
  355.  
  356.     while (tmp != NULL) // найдена лексема
  357.     {
  358.         if (strcmp(tmp, "EXP") == 0) tmp = EXP;
  359.         if (strcmp(tmp, "PI") == 0) tmp = PI;
  360.  
  361.         if (isNumber(tmp) == 1) // лексема - число
  362.         {
  363.             stackPush(atof(tmp), &myStack); // запись числа в стек
  364.         }//if
  365.         else if (isOperator(tmp) == 1) // лексема - оператор
  366.         {
  367.             if (myStack->size >= 2) // в стеке 2 числа или более
  368.             {
  369.                 stackPush(operate(*tmp, &myStack, errCode), &myStack); // в стек результата операции
  370.             }//if
  371.             else
  372.             {
  373.                 stackClear(&myStack); // очистка стека
  374.                 *errCode = 2;
  375.                 return res;
  376.             }//else
  377.         }//else if
  378.         else // встречена переменная
  379.         {
  380.             for (i = 0; i < *varCount; i++)
  381.             {
  382.                 // имя переменной в массиве переменных найдено
  383.                 if (strcmp(tmp, (*varList)[i]->name) == 0)
  384.                 {
  385.                     stackPush((*varList)[i]->value, &myStack); // запись значения переменной в стек
  386.                 }//if
  387.             }//for
  388.         }//else
  389.         tmp = strtok(NULL, "\t "); // переход к следующей лексеме
  390.     }//while
  391.     res = stackPop(&myStack);
  392.     stackClear(&myStack);
  393.     return res;
  394. }//calc
  395.  
  396. int parsStr(char* str, var*** varList, int* varCount )
  397. {
  398.     int operandCount = 0; // число операндов
  399.     int operateCount = 0; // число операторов
  400.     char* tmp = NULL; // указатель на лексему
  401.     int i; // индексная переменная
  402.     int indicator = 0; // код завершения функции
  403.     int knownVariable = 0; // флаг уникальности переменной
  404.  
  405.     tmp = strtok(str, "\t "); // считывание лексемы
  406.  
  407.     while (tmp != NULL)
  408.     {
  409.         knownVariable = 0;
  410.         if (strcmp(tmp, "EXP") == 0) // лексема - экспонента
  411.         {
  412.             tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  413.             operandCount++; // увеличение на 1 счетчика числа операндов
  414.             continue;
  415.         }//if
  416.  
  417.         if (strcmp(tmp, "PI") == 0) // лексема - число Пи
  418.         {
  419.             tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  420.             operandCount++; // увеличение на 1 счетчика числа операндов
  421.             continue;
  422.         }//if
  423.  
  424.         if (isOperator(tmp) == 1) // лексема - оператор
  425.         {
  426.             operateCount++; // увеличение на 1 счетчика числа операторов
  427.         }//if
  428.         else  if (isNumber(tmp) == 1) // лексема - число
  429.         {
  430.             operandCount++; // увеличение на 1 счетчика числа операндов
  431.  
  432.         }//else if
  433.         else if (validVarName(tmp) == 1) // может ли лексема являться именем переменной
  434.         {
  435.             operandCount++;  // увеличение на 1 счетчика числа операндов
  436.             // проверка имени переменной на уникальность
  437.             for (i = 0; i < *varCount; i++)
  438.             {
  439.                 if (strcmp(tmp, (*varList)[i]->name) == 0) // переменная не уникальна
  440.                 {
  441.                     knownVariable = 1;
  442.                     break;
  443.                 }//if
  444.             }//for
  445.  
  446.             if (knownVariable == 1)
  447.             {
  448.                 tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  449.                 continue;
  450.             }//if
  451.             else indicator = createVariable(tmp, varList, varCount); // флаг создалась ли переменная: 0 - да, -1 - нет
  452.            
  453.         }//else if
  454.         else
  455.         {
  456.             indicator = -2; // флаг -2, встречена неизвестная лексема
  457.             return indicator;
  458.         }//else
  459.  
  460.         tmp = strtok(NULL, "\t "); // указатель на следующую лексему
  461.     }//while
  462.  
  463.     if (operateCount != operandCount - 1) // недостаточное число операторов или операндов
  464.     {
  465.         indicator = -3;
  466.     }//if
  467.     return indicator;
  468. }//parsStr
  469.  
  470. void printError(int errCode)
  471. {
  472.     switch (errCode)
  473.     {
  474.     case 0:
  475.         return;
  476.     case -1:
  477.         printf("\nОшибка! Невозможно выделить память\n\n");
  478.         return;
  479.     case -2:
  480.         printf("\nОшибка! Встречена неизвестная лексема\n\n");
  481.         return;
  482.     case -3:
  483.         printf("\nОшибка! Недостаточно операторов или операндов\n\n");
  484.         return;
  485.     case 1:
  486.         printf("\nОшибка! Невозможно выделить память под стек\n\n");
  487.         return;
  488.     case 2:
  489.         printf("\nОшибка! Встречен оператор, а количество операндов в стеке меньше двух\n\n");
  490.         return;
  491.     case 3:
  492.         printf("\nОшибка! Деление на 0\n\n");
  493.         return;
  494.     case 4:
  495.         printf("\nОшибка! Недопустимое значение переменной\n\n");
  496.         return;
  497.     case 5:
  498.         printf("\nОшибка! Невозможно выделить память под копию строки\n\n");
  499.         return;
  500.     default:
  501.         printf("\nНеизвестный код ошибки.\n\n");
  502.         return;
  503.     }//switch
  504. }//printError
Add Comment
Please, Sign In to add comment