Advertisement
baadgeorge

kr_latest3

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