Advertisement
baadgeorge

kr

Dec 13th, 2020
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 15.80 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 SIZESTACK 3
  11. #define EXP "2,7182818"
  12. #define PI  "3,1415926"
  13.  
  14. // определение структуры для переменных
  15. struct _var
  16. {
  17.     char* name; // имя переменной
  18.     double value; // значение переменной
  19. };
  20.  
  21. // определение имени var для типа _var
  22. typedef struct _var var;
  23.  
  24. var** varList = NULL; // двойной указатель на массив переменных
  25.  
  26. int varCount = 0; // число уникальных переменных
  27. int operandCount = 0; // число операндов
  28. int operateCount = 0; // число операторов
  29. int errCalc = 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 (errCalc == 0) // ошибок не выявлено
  161.         {
  162.             printf("\nРезультат: %lf\n\n", checkCalc);
  163.         }
  164.         else
  165.         {
  166.             // выод сообщения об ошибке в соответствии с ее кодом
  167.             switch ((int)checkCalc)
  168.             {
  169.             case 1:
  170.                 printf("\nОшибка! Невозможно выделить память под стек.\n\n");
  171.                 break;
  172.             case 2:
  173.                 printf("\nОшибка! Встречен оператор, а количество чисел в стеке меньше двух.\n\n");
  174.                 break;
  175.             case 3:
  176.                 printf("\nОшибка! После завершения вычислений в стеке содержится не единственное число.\n\n");
  177.                 break;
  178.             case 4:
  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.     double op2 = stackPop(myStack);
  291.     double op1 = stackPop(myStack);
  292.     switch (operator)
  293.     {
  294.     case '+':
  295.         return op1 + op2;
  296.     case '-':
  297.         return op1 - op2;
  298.     case '*':
  299.         return op1 * op2;
  300.     case '/':
  301.         return op1 / op2;
  302.     case '^':
  303.         return powf(op1, op2);
  304.     }
  305.    
  306. }
  307.  
  308. int isOperator(char* str)
  309. {
  310.     // в лексеме найден символ принадлежащий к списку операторов и длига лексемы 1
  311.     if (strpbrk(str, "+-/*^") != NULL && strlen(str) == 1)
  312.     {
  313.         return 1;
  314.     }
  315.     else
  316.     {
  317.         return 0;
  318.     }
  319. }
  320.  
  321. int isNumber(char* str)
  322. {
  323.     int i = 0; // индексная переменная
  324.     int foundPoint = 0; // флаг найден ли символ разделитель в вещественном числе
  325.  
  326.     // проходим по всем символам лексемы
  327.     for (i = 0; i < strlen(str); i++)
  328.     {
  329.         if (isdigit(str[i]) == 0) // текущий символ не число
  330.         {
  331.             if (str[i] == ',') // текущий символ - разделитель в вещественном числе
  332.             {
  333.                 if (foundPoint == 0) // символ разделитель ранее не встречен
  334.                 {
  335.                     foundPoint = 1; // флаг - символ разделитель найден
  336.                 }
  337.                 else
  338.                 {
  339.                     return 0;
  340.                 }
  341.             }
  342.             else
  343.             {
  344.                 return 0;
  345.             }
  346.         }
  347.     }
  348.     return 1;
  349. }
  350.  
  351. int validVarName(char* str)
  352. {
  353.     int i = 0; // индексная переменная
  354.  
  355.     if (isalpha(str[0]) == 0) // первый символ - не буква
  356.     {
  357.         return 0;
  358.     }
  359.  
  360.     // проходим по всем элементам лексемы
  361.     for (i = 1; i < strlen(str); i++)
  362.     {
  363.         if (isalnum(str[i]) == 0) // текущий символ - не буква и не число
  364.         {
  365.             return 0;
  366.         }
  367.     }
  368.  
  369.     return 1;
  370. }
  371.  
  372. double calc(char* str)
  373. {
  374.     double res = 0; // результат вычислений
  375.     char* tmp = NULL; // указатель на лексему
  376.     int i = 0; // индексная переменная
  377.     stack* myStack = stackInit(); // создание стека
  378.  
  379.     if (myStack == NULL) // память под стек не была выделена
  380.     {
  381.         errCalc = 1; // флаг найдена ошибка
  382.         return 1.0; // код ошибки
  383.     }
  384.  
  385.     tmp = strtok(str, "\t "); // считывание лексемы
  386.  
  387.     while (tmp != NULL) // найдена лексема
  388.     {
  389.  
  390.         if (strcmp(tmp, "EXP") == 0) tmp = EXP;
  391.         if (strcmp(tmp, "PI") == 0) tmp = PI;
  392.  
  393.         if (isNumber(tmp) == 1) // лексема - число
  394.         {
  395.             stackPush(atof(tmp), &myStack); // запись числа в стек
  396.         }
  397.         else if (isOperator(tmp) == 1) // лексема - оператор
  398.         {
  399.             if (myStack->size >= 2) // в стеке 2 числа или более
  400.             {
  401.                 stackPush(operate(*tmp, &myStack), &myStack); // в стек результата операции
  402.             }
  403.             else
  404.             {
  405.                 stackClear(&myStack); // очистка стека
  406.                 errCalc = 1; // флаг найдена ошибка
  407.                 return 2.0;  // код ошибки
  408.             }
  409.         }
  410.         else // встречена переменная
  411.         {
  412.             for (i = 0; i < varCount; i++)
  413.             {
  414.                 // имя переменной в массиве переменных найдено
  415.                 if (strcmp(tmp, varList[i]->name) == 0)
  416.                 {
  417.                     stackPush(varList[i]->value, &myStack); // запись значения переменной в стек
  418.                 }
  419.             }
  420.            
  421.         }
  422.         tmp = strtok(NULL, "\t "); // переход к следующей лексеме
  423.     }
  424.  
  425.     if (myStack->size > 1) // после вычислений в стеке больше 1 элемента
  426.     {
  427.         stackClear(&myStack);
  428.         errCalc = 1;
  429.         return 3.0;
  430.     }
  431.    
  432.     if (myStack->size == 0) //
  433.     {
  434.         stackClear(&myStack);
  435.         errCalc = 1;
  436.         return 4.0;
  437.     }
  438.     res = stackPop(&myStack);
  439.     stackClear(&myStack);
  440.     return res;
  441. }
  442.  
  443. int parsStr(char* str)
  444. {
  445.     char* tmp = NULL;
  446.     int i = 0;
  447.     int indicator = 0;
  448.     int knownVariable = 0;
  449.  
  450.     tmp = strtok(str, "\t ");
  451.  
  452.     while (tmp != NULL)
  453.     {
  454.         knownVariable = 0;
  455.         if (strcmp(tmp, "EXP") == 0)
  456.         {
  457.             tmp = strtok(NULL, "\t ");
  458.             operandCount++;
  459.             continue;
  460.         }
  461.         if (strcmp(tmp, "PI") == 0)
  462.         {
  463.             tmp = strtok(NULL, "\t ");
  464.             operandCount++;
  465.             continue;
  466.         }
  467.  
  468.         if (isOperator(tmp) == 1)
  469.         {
  470.             operateCount++;
  471.         }
  472.  
  473.         if (isNumber(tmp) == 0 && isOperator(tmp) == 0)
  474.         {
  475.             if (validVarName(tmp) == 1)
  476.             {
  477.                 operandCount++;
  478.                 for (i = 0; i < varCount; i++)
  479.                 {
  480.                     if (strcmp(tmp, varList[i]->name) == 0)
  481.                     {
  482.                         knownVariable = 1;
  483.                         break;
  484.                     }
  485.                 }
  486.                 if (knownVariable == 1)
  487.                 {
  488.                     tmp = strtok(NULL, "\t ");
  489.                     continue;
  490.                 }
  491.                 indicator = createVariable(tmp);
  492.  
  493.             }
  494.             else
  495.             {
  496.                 indicator = -1;
  497.             }
  498.         }
  499.         tmp = strtok(NULL, "\t ");
  500.     }
  501.     return indicator;
  502. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement