Advertisement
baadgeorge

Untitled

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